Check-in [6d1e1922b6]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:docks view
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 6d1e1922b63a259e46b6746ab30b9034ce102931
User & Date: linnaea 2016-10-27 13:01:47
Context
2016-10-27
13:32
downgrade to .NET FX 4.5.2 check-in: 9f7c2c746c user: linnaea tags: trunk
13:01
docks view check-in: 6d1e1922b6 user: linnaea tags: trunk
2016-10-24
12:37
update equipment list when new ship is added check-in: afaf915d7c user: linnaea tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to Linnaea.Network.Protocols/Http/Http1Session.cs.

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
                    } else {
                        client = value.Destination; server = value.Source;
                    }
                }

                if(Equals(client, value.Source)) {
                    qRequests.Enqueue(value.Data);
                    OnRequest(value.Data);
                } else if(Equals(server, value.Source)) {
                    res = value.Data;
                    if(qRequests.Count > 0) {
                        req = qRequests.Dequeue();
                        res.MaxBufferedBody = req.MaxBufferedBody;
                    }
                } else {
                    throw new InvalidOperationException();
                }
            }

            if(res != null) {
                if(res.MaxBufferedBody <= 0) {
                    Emit(new Http1Session(req, res, server, client));
                } else {
                    res.Subscribe(_ => { }, () => Emit(new Http1Session(req, res, server, client)));
                }
            }
        }

        protected virtual void OnRequest(HttpMessage msg)
        {
            onRequest?.Invoke(msg);
        }
    }
    
    public class Http1Session
    {
        public HttpMessage Request { get; }
        public HttpMessage Response { get; }
        public EndPoint Client { get; }







|



















<
<
<
<
<







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52





53
54
55
56
57
58
59
                    } else {
                        client = value.Destination; server = value.Source;
                    }
                }

                if(Equals(client, value.Source)) {
                    qRequests.Enqueue(value.Data);
                    onRequest?.Invoke(value.Data);
                } else if(Equals(server, value.Source)) {
                    res = value.Data;
                    if(qRequests.Count > 0) {
                        req = qRequests.Dequeue();
                        res.MaxBufferedBody = req.MaxBufferedBody;
                    }
                } else {
                    throw new InvalidOperationException();
                }
            }

            if(res != null) {
                if(res.MaxBufferedBody <= 0) {
                    Emit(new Http1Session(req, res, server, client));
                } else {
                    res.Subscribe(_ => { }, () => Emit(new Http1Session(req, res, server, client)));
                }
            }
        }





    }
    
    public class Http1Session
    {
        public HttpMessage Request { get; }
        public HttpMessage Response { get; }
        public EndPoint Client { get; }

Changes to WarshipGirlsRSniffer/App.xaml.cs.

36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

            captureSource = new Linnaea.Network.Captures.Sources.TcpServer(5000);
            var frames = captureSource.Select(x => x.ParsePcap()).FirstActive();

            //var captureSource = new Linnaea.Network.Captures.Sources.TcpClient("127.0.0.1", 49000);
            //var frames = captureSource.ParsePcap();

            var sessions = new IObservable<Linnaea.Network.CaptureFrame>[] {
                frames,
                frames.ParseEthernet().ToCaptureFrame()
            }.AllActive(true)
                .ParseIp().ParseTcpPacket().ToTcpSessions()
                .Select(
                    x => x.ParseHttp1Messages()
                          .ParseHttp1Sessions(msg => msg.MaxBufferedBody = msg.Host?.EndsWith(".jr.moefantasy.com") == true ? 1 << 19 : 0)







|







36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

            captureSource = new Linnaea.Network.Captures.Sources.TcpServer(5000);
            var frames = captureSource.Select(x => x.ParsePcap()).FirstActive();

            //var captureSource = new Linnaea.Network.Captures.Sources.TcpClient("127.0.0.1", 49000);
            //var frames = captureSource.ParsePcap();

            var sessions = new[] {
                frames,
                frames.ParseEthernet().ToCaptureFrame()
            }.AllActive(true)
                .ParseIp().ParseTcpPacket().ToTcpSessions()
                .Select(
                    x => x.ParseHttp1Messages()
                          .ParseHttp1Sessions(msg => msg.MaxBufferedBody = msg.Host?.EndsWith(".jr.moefantasy.com") == true ? 1 << 19 : 0)

Changes to WarshipGirlsRSniffer/View/Controls/ShipStatus.xaml.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<UserControl x:Class="WarshipGirlsRSniffer.View.Controls.ShipStatus"
             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:WarshipGirlsRSniffer.View.Controls"
             xmlns:vm="clr-namespace:WarshipGirlsRSniffer.Vm"
             mc:Ignorable="d" d:DesignWidth="300" d:DataContext="{d:DesignInstance vm:ShipVm}">
    <TextBlock TextAlignment="Center" Padding="9,3">
        <TextBlock.Style>
            <Style TargetType="TextBlock">
                <Setter Property="Text" Value="----" />
                <Setter Property="Background" Value="LightGray" />

                <Style.Triggers>







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<UserControl x:Class="WarshipGirlsRSniffer.View.Controls.ShipStatus"
             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:WarshipGirlsRSniffer.View.Controls"
             xmlns:vm="clr-namespace:WarshipGirlsRSniffer.Vm"
             mc:Ignorable="d" d:DesignWidth="60" d:DataContext="{d:DesignInstance vm:ShipVm}">
    <TextBlock TextAlignment="Center" Padding="9,3">
        <TextBlock.Style>
            <Style TargetType="TextBlock">
                <Setter Property="Text" Value="----" />
                <Setter Property="Background" Value="LightGray" />

                <Style.Triggers>

Added WarshipGirlsRSniffer/View/Converter/BuildShipTypeToDescriptionConverter.cs.























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
using System;
using System.Globalization;
using System.Windows.Data;

namespace WarshipGirlsRSniffer.View.Converter
{
    public class BuildShipTypeToDescriptionConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if(!(value is Vo.BuildShipType)) {
                return null;
            }

            switch((Vo.BuildShipType)value) {
                case Vo.BuildShipType.Cruiser: return "巡洋舰";
                case Vo.BuildShipType.Destroyer: return "驱逐舰";
                default:return (byte)(Vo.BuildShipType)value + "类";
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

Added WarshipGirlsRSniffer/View/Docks.xaml.































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<UserControl x:Class="WarshipGirlsRSniffer.View.Docks"
             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:WarshipGirlsRSniffer.View"
             xmlns:vm="clr-namespace:WarshipGirlsRSniffer.Vm"
             mc:Ignorable="d" d:DataContext="{d:DesignInstance vm:VmDock}"
             d:DesignHeight="300" d:DesignWidth="300">
    <UserControl.Resources>
        <DataTemplate x:Key="dockTemplate">
            <Border Padding="5" Margin="0,0,0,5" BorderThickness="0,0,0,1" BorderBrush="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="Auto" />
                    </Grid.ColumnDefinitions>

                    <TextBlock Grid.Column="0" Grid.Row="0" Grid.RowSpan="2" Text="{Binding Id}" VerticalAlignment="Center" Margin="10,0" FontSize="16" />
                    <TextBlock Grid.Column="1" Grid.Row="0" Text="{Binding Title}" Margin="0,4" FontSize="14" />
                    <TextBlock Grid.Column="1" Grid.Row="1" Text="{Binding RemainingTime, StringFormat={}{0:hh':'mm':'ss}}" Margin="0,4" />
                </Grid>
                <Border.Style>
                    <Style TargetType="Border">
                        <Setter Property="Visibility" Value="Visible" />
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding Locked}" Value="True">
                                <Setter Property="Visibility" Value="Collapsed" />
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </Border.Style>
            </Border>
        </DataTemplate>
        <ItemsPanelTemplate x:Key="stackTemplate">
            <StackPanel Orientation="Vertical" />
        </ItemsPanelTemplate>
    </UserControl.Resources>
    
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>

        <Border Grid.Column="0" BorderThickness="0,0,1,1" BorderBrush="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}"><TextBlock Text="修理渠" TextAlignment="Center" FontSize="14" Padding="2" /></Border>
        <Border Grid.Column="1" BorderThickness="0,0,1,1" BorderBrush="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}"><TextBlock Text="建造渠" TextAlignment="Center" FontSize="14" Padding="2" /></Border>
        <Border Grid.Column="2" BorderThickness="0,0,0,1" BorderBrush="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}"><TextBlock Text="装备渠" TextAlignment="Center" FontSize="14" Padding="2" /></Border>

        <ItemsControl BorderThickness="0,0,1,1" BorderBrush="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}" Grid.Row="1" Grid.Column="0" Padding="5,0" ItemTemplate="{StaticResource dockTemplate}" ItemsPanel="{StaticResource stackTemplate}" ItemsSource="{Binding RepairDock}" />
        <ItemsControl BorderThickness="0,0,1,1" BorderBrush="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}" Grid.Row="1" Grid.Column="1" Padding="5,0" ItemTemplate="{StaticResource dockTemplate}" ItemsPanel="{StaticResource stackTemplate}" ItemsSource="{Binding BuildDock}" />
        <ItemsControl BorderThickness="0,0,0,1" BorderBrush="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}" Grid.Row="1" Grid.Column="2" Padding="5,0" ItemTemplate="{StaticResource dockTemplate}" ItemsPanel="{StaticResource stackTemplate}" ItemsSource="{Binding EquipmentDock}" />
    </Grid>
</UserControl>

Added WarshipGirlsRSniffer/View/Docks.xaml.cs.

























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WarshipGirlsRSniffer.View
{
    /// <summary>
    /// Docks.xaml 的交互逻辑
    /// </summary>
    public partial class Docks : UserControl
    {
        public Docks()
        {
            InitializeComponent();
        }
    }
}

Changes to WarshipGirlsRSniffer/View/MainWindow.xaml.

40
41
42
43
44
45
46

47
48
49
50

        <control:VerticalTabView Grid.Row="1" DataContext="{Binding CurrentSession, Mode=OneWay}">
            <x:Array Type="FrameworkElement">
                <local:Fleets control:TabView.TabName="舰队" DataContext="{Binding Yard.Fleets}" />
                <local:Fleets control:TabView.TabName="战役舰队" DataContext="{Binding Yard.CampaignFleets}" />
                <!--<local:Ships control:TabView.TabName="舰船" DataContext="{Binding Yard.Ships}" />-->
                <local:Equipments control:TabView.TabName="装备" DataContext="{Binding Yard.Equipments}" />

            </x:Array>
        </control:VerticalTabView>
    </Grid>
</Window>







>




40
41
42
43
44
45
46
47
48
49
50
51

        <control:VerticalTabView Grid.Row="1" DataContext="{Binding CurrentSession, Mode=OneWay}">
            <x:Array Type="FrameworkElement">
                <local:Fleets control:TabView.TabName="舰队" DataContext="{Binding Yard.Fleets}" />
                <local:Fleets control:TabView.TabName="战役舰队" DataContext="{Binding Yard.CampaignFleets}" />
                <!--<local:Ships control:TabView.TabName="舰船" DataContext="{Binding Yard.Ships}" />-->
                <local:Equipments control:TabView.TabName="装备" DataContext="{Binding Yard.Equipments}" />
                <local:Docks control:TabView.TabName="船渠" DataContext="{Binding Dock}" />
            </x:Array>
        </control:VerticalTabView>
    </Grid>
</Window>

Changes to WarshipGirlsRSniffer/Vm/BuildDockVm.cs.



1
2
3
4
5
6


7
8

9
10
11
12

















13
14
15
16
17
18

















19
20
21


using WarshipGirlsRSniffer.Vo;

namespace WarshipGirlsRSniffer.Vm
{
    public class BuildDockVm : VmBase<BuildDockVm>
    {


        private BuildDock vo;
        private readonly VmDock dock;


        public BuildDock Vo {
            get { return vo; }
            set { vo = value; RaiseMultiPropertyChanged(); }

















        }

        public BuildDockVm(BuildDock vo, VmDock dock)
        {
            this.vo = vo;
            this.dock = dock;

















        }
    }
}
>
>






>
>


>



|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>






>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
using System;
using System.Threading;
using WarshipGirlsRSniffer.Vo;

namespace WarshipGirlsRSniffer.Vm
{
    public class BuildDockVm : VmBase<BuildDockVm>
    {
        private static readonly View.Converter.BuildShipTypeToDescriptionConverter cvt = new View.Converter.BuildShipTypeToDescriptionConverter();

        private BuildDock vo;
        private readonly VmDock dock;
        private readonly Timer timer;

        public BuildDock Vo {
            get { return vo; }
            set { vo = value; RaiseMultiPropertyChanged(); UpdateTimer(this); }
        }

        private DateTimeOffset? _endTime;
        public DateTimeOffset? EndTime => _endTime;
        public byte Id => vo.id;
        public bool Locked => vo.locked != 0;
        public BuildShipType ShipType => (BuildShipType)vo.shipType;
        public string Title => cvt.Convert(ShipType, typeof(string), null, null) as string;
        public TimeSpan? RemainingTime {
            get
            {
                if(_endTime == null) {
                    return null;
                }
                var delta = _endTime.Value - DateTimeOffset.Now;
                return delta.Ticks < 0 ? TimeSpan.Zero : delta;
            }
        }

        public BuildDockVm(BuildDock vo, VmDock dock)
        {
            this.vo = vo;
            this.dock = dock;

            timer = new Timer(UpdateTimer, null, -1, -1);
            UpdateTimer(this);
        }

        private void UpdateTimer(object _)
        {
            RaisePropertyChanged(nameof(RemainingTime));
            if(_ != null) {
                _endTime = vo.endTime == 0 ? (DateTimeOffset?)null : DateTimeOffset.FromUnixTimeSeconds(vo.endTime);
                if(RemainingTime.HasValue && RemainingTime != TimeSpan.Zero) {
                    timer.Change(1000, 1000);
                }
            }
            if(!RemainingTime.HasValue || RemainingTime == TimeSpan.Zero) {
                timer.Change(-1, -1);
            }
        }
    }
}

Changes to WarshipGirlsRSniffer/Vm/EquipmentDockVm.cs.



1
2
3
4
5
6
7
8

9
10
11
12

















13
14
15
16
17
18

















19
20
21


using WarshipGirlsRSniffer.Vo;

namespace WarshipGirlsRSniffer.Vm
{
    public class EquipmentDockVm : VmBase<RepairDockVm>
    {
        private EquipmentDock vo;
        private readonly VmDock dock;


        public EquipmentDock Vo {
            get { return vo; }
            set { vo = value; RaiseMultiPropertyChanged(); }

















        }

        public EquipmentDockVm(EquipmentDock vo, VmDock dock)
        {
            this.vo = vo;
            this.dock = dock;

















        }
    }
}
>
>








>



|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>






>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
using System;
using System.Threading;
using WarshipGirlsRSniffer.Vo;

namespace WarshipGirlsRSniffer.Vm
{
    public class EquipmentDockVm : VmBase<RepairDockVm>
    {
        private EquipmentDock vo;
        private readonly VmDock dock;
        private readonly Timer timer;

        public EquipmentDock Vo {
            get { return vo; }
            set { vo = value; RaiseMultiPropertyChanged(); UpdateTimer(this); }
        }

        private DateTimeOffset? _endTime;
        public DateTimeOffset? EndTime => _endTime;
        public byte Id => vo.id;
        public bool Locked => vo.locked != 0;
        public string Title => Equipment.title;
        public ShipEquipment Equipment => Client.WGRSession.InitTxt.ShipEquipment[vo.equipmentCid];
        public TimeSpan? RemainingTime {
            get
            {
                if(_endTime == null) {
                    return null;
                }
                var delta = _endTime.Value - DateTimeOffset.Now;
                return delta.Ticks < 0 ? TimeSpan.Zero : delta;
            }
        }

        public EquipmentDockVm(EquipmentDock vo, VmDock dock)
        {
            this.vo = vo;
            this.dock = dock;

            timer = new Timer(UpdateTimer, null, -1, -1);
            UpdateTimer(this);
        }

        private void UpdateTimer(object _)
        {
            RaisePropertyChanged(nameof(RemainingTime));
            if(_ != null) {
                _endTime = vo.endTime == 0 ? (DateTimeOffset?)null : DateTimeOffset.FromUnixTimeSeconds(vo.endTime);
                if(RemainingTime.HasValue && RemainingTime != TimeSpan.Zero) {
                    timer.Change(1000, 1000);
                }
            }
            if(!RemainingTime.HasValue || RemainingTime == TimeSpan.Zero) {
                timer.Change(-1, -1);
            }
        }
    }
}

Changes to WarshipGirlsRSniffer/Vm/RepairDockVm.cs.



1
2
3
4
5
6
7
8

9
10
11
12

















13
14
15
16
17
18

















19
20
21


using WarshipGirlsRSniffer.Vo;

namespace WarshipGirlsRSniffer.Vm
{
    public class RepairDockVm : VmBase<RepairDockVm>
    {
        private RepairDock vo;
        private readonly VmDock dock;


        public RepairDock Vo {
            get { return vo; }
            set { vo = value; RaiseMultiPropertyChanged(); }

















        }

        public RepairDockVm(RepairDock vo, VmDock dock)
        {
            this.vo = vo;
            this.dock = dock;

















        }
    }
}
>
>








>



|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>






>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
using System;
using System.Threading;
using WarshipGirlsRSniffer.Vo;

namespace WarshipGirlsRSniffer.Vm
{
    public class RepairDockVm : VmBase<RepairDockVm>
    {
        private RepairDock vo;
        private readonly VmDock dock;
        private readonly Timer timer;

        public RepairDock Vo {
            get { return vo; }
            set { vo = value; RaiseMultiPropertyChanged(); UpdateTimer(this); }
        }

        private DateTimeOffset? _endTime;
        public DateTimeOffset? EndTime => _endTime;
        public byte Id => vo.id;
        public bool Locked => vo.locked != 0;
        public string Title => Ship?.Name;
        public ShipVm Ship => dock.Session.Yard.Ships[vo.shipId];
        public TimeSpan? RemainingTime {
            get
            {
                if(_endTime == null) {
                    return null;
                }
                var delta = _endTime.Value - DateTimeOffset.Now;
                return delta.Ticks < 0 ? TimeSpan.Zero : delta;
            }
        }

        public RepairDockVm(RepairDock vo, VmDock dock)
        {
            this.vo = vo;
            this.dock = dock;

            timer = new Timer(UpdateTimer, null, -1, -1);
            UpdateTimer(this);
        }

        private void UpdateTimer(object _)
        {
            RaisePropertyChanged(nameof(RemainingTime));
            if(_ != null) {
                _endTime = vo.endTime == 0 ? (DateTimeOffset?)null : DateTimeOffset.FromUnixTimeSeconds(vo.endTime);
                if(RemainingTime.HasValue && RemainingTime != TimeSpan.Zero) {
                    timer.Change(1000, 1000);
                }
            }
            if(!RemainingTime.HasValue || RemainingTime == TimeSpan.Zero) {
                timer.Change(-1, -1);
            }
        }
    }
}

Changes to WarshipGirlsRSniffer/Vm/VmBase.cs.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;

namespace WarshipGirlsRSniffer.Vm
{
    [Serializable]
    public abstract class VmBase<T> : INotifyPropertyChanged
        where T : VmBase<T>
    {
        private static IReadOnlyDictionary<string, IReadOnlyCollection<string>> _propertyChangePath = null;
        private static Lazy<string[]> _allProperties;
        
        protected virtual IReadOnlyDictionary<string, IReadOnlyCollection<string>> PropertyDependency => null;

        [field: NonSerialized]












|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;

namespace WarshipGirlsRSniffer.Vm
{
    [Serializable]
    public abstract class VmBase<T> : INotifyPropertyChanged
        //where T : VmBase<T>
    {
        private static IReadOnlyDictionary<string, IReadOnlyCollection<string>> _propertyChangePath = null;
        private static Lazy<string[]> _allProperties;
        
        protected virtual IReadOnlyDictionary<string, IReadOnlyCollection<string>> PropertyDependency => null;

        [field: NonSerialized]
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
            return handle;
        }

        [OnDeserialized]
        private void Deserialized(StreamingContext context)
        {
            if(_allProperties == null) {
                System.Threading.Interlocked.CompareExchange(ref _allProperties, new Lazy<string[]>(() => {
                    return GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).Select(info => info.Name).ToArray();
                }), null);
            }

            if(_propertyChangePath != null) return;
            var pdNames = PropertyDependency;
            if(pdNames == null) {
                return;
            }

            var _cp = new Dictionary<string, HashSet<string>>();
            var closed = new HashSet<string>();
            var open = new LinkedList<string>();
            foreach(var dpPair in PropertyDependency) {                    //Resolve all depencency of one particular property
                if(dpPair.Key == null) continue;

                closed.Clear(); open.Clear();
                open.AddLast(dpPair.Key);
                while(open.First != null) {
                    var visit = open.First.Value;
                    open.RemoveFirst();
                    if(!closed.Add(visit)) continue;
                    if(!PropertyDependency.ContainsKey(visit)) continue;
                    foreach(var dp in PropertyDependency[visit]) {
                        if(dp != null) open.AddLast(dp);
                    }
                }
                foreach(var source in closed) {                             //Flip the dependency list to form the lookup table
                    if(!_cp.ContainsKey(source)) {
                        _cp[source] = new HashSet<string>();
                        _cp[source].Add(source);
                    }
                    _cp[source].Add(dpPair.Key);
                }
            }

            System.Threading.Interlocked.CompareExchange(ref _propertyChangePath, _cp.ToDictionary(x => x.Key, x => x.Value.ToArray() as IReadOnlyCollection<string>), null);
        }

        protected void RaisePropertyChanged([CallerMemberName] string property = null)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if(handler == null) return;
            lock(_suppressNotification)







|
|
|








|

















<
<
|
<
<



|







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68


69


70
71
72
73
74
75
76
77
78
79
80
            return handle;
        }

        [OnDeserialized]
        private void Deserialized(StreamingContext context)
        {
            if(_allProperties == null) {
                System.Threading.Interlocked.CompareExchange(ref _allProperties, new Lazy<string[]>(() =>
                    GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).Select(info => info.Name).ToArray()
                ), null);
            }

            if(_propertyChangePath != null) return;
            var pdNames = PropertyDependency;
            if(pdNames == null) {
                return;
            }

            var _cp = MultiValueDictionary<string, string>.Create<HashSet<string>>();
            var closed = new HashSet<string>();
            var open = new LinkedList<string>();
            foreach(var dpPair in PropertyDependency) {                    //Resolve all depencency of one particular property
                if(dpPair.Key == null) continue;

                closed.Clear(); open.Clear();
                open.AddLast(dpPair.Key);
                while(open.First != null) {
                    var visit = open.First.Value;
                    open.RemoveFirst();
                    if(!closed.Add(visit)) continue;
                    if(!PropertyDependency.ContainsKey(visit)) continue;
                    foreach(var dp in PropertyDependency[visit]) {
                        if(dp != null) open.AddLast(dp);
                    }
                }
                foreach(var source in closed) {                             //Flip the dependency list to form the lookup table


                    _cp.Add(source, dpPair.Key);


                }
            }

            System.Threading.Interlocked.CompareExchange(ref _propertyChangePath, _cp, null);
        }

        protected void RaisePropertyChanged([CallerMemberName] string property = null)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if(handler == null) return;
            lock(_suppressNotification)

Changes to WarshipGirlsRSniffer/Vm/VmDock.cs.

11
12
13
14
15
16
17

18
19
20


21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
    public class VmDock
    {
        private CompositeDisposable _disposable = new CompositeDisposable();

        public DefaultTable<BuildDockVm> BuildDock { get; } = new DefaultTable<BuildDockVm>();
        public DefaultTable<RepairDockVm> RepairDock { get; } = new DefaultTable<RepairDockVm>();
        public DefaultTable<EquipmentDockVm> EquipmentDock { get; } = new DefaultTable<EquipmentDockVm>();


        public VmDock(VmSession _)
        {


            _disposable.Add(_.Session.Api_Api_InitGame.Subscribe(OnGameInit));

            _disposable.Add(_.Session.Api_Boat_Repair.Subscribe(p => p.Item2.repairDockVo.ForEach(UpdateDock)));
            _disposable.Add(_.Session.Api_Boat_RepairComplete.Subscribe(p => p.Item2.repairDockVo.ForEach(UpdateDock)));
            _disposable.Add(_.Session.Api_Boat_InstantRepair.Subscribe(p => p.Item2.repairDockVo.ForEach(UpdateDock)));
            _disposable.Add(_.Session.Api_Dock_BuildBoat.Subscribe(p => p.Item2.dockVo.ForEach(UpdateDock)));
            _disposable.Add(_.Session.Api_Dock_BuildEquipment.Subscribe(p => p.Item2.equipmentDockVo.ForEach(UpdateDock)));
            _disposable.Add(_.Session.Api_Dock_GetBoat.Subscribe(p => p.Item2.dockVo.ForEach(UpdateDock)));
            _disposable.Add(_.Session.Api_Dock_GetEquipment.Subscribe(p => p.Item2.equipmentDockVo.ForEach(UpdateDock)));
            _disposable.Add(_.Session.Api_Dock_InstantBuild.Subscribe(p => p.Item2.dockVo.ForEach(UpdateDock)));
            _disposable.Add(_.Session.Api_Dock_InstantEquipmentBuild.Subscribe(p => p.Item2.equipmentDockVo.ForEach(UpdateDock)));
        }

        private void OnGameInit(Tuple<Protocol.Request.Api.InitGame, Protocol.Response.Api.InitGame> p)
        {
            App.BeginDispatcherInvoke(() => {
                BuildDock.Clear();
                RepairDock.Clear();
                EquipmentDock.Clear();

                p.Item2.dockVo.ForEach(x => BuildDock[x.id] = new BuildDockVm(x, this));
                p.Item2.repairDockVo.ForEach(x => RepairDock[x.id] = new RepairDockVm(x, this));
                p.Item2.equipmentDockVo.ForEach(x => EquipmentDock[x.id] = new EquipmentDockVm(x, this));
            });
        }

        private void UpdateDock(Vo.BuildDock vo)
        {
            var dock = BuildDock[vo.id];
            if(dock != null) {
                dock.Vo = vo;







>



>
>















<
<
<
<
<
|
|
|
<







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38





39
40
41

42
43
44
45
46
47
48
    public class VmDock
    {
        private CompositeDisposable _disposable = new CompositeDisposable();

        public DefaultTable<BuildDockVm> BuildDock { get; } = new DefaultTable<BuildDockVm>();
        public DefaultTable<RepairDockVm> RepairDock { get; } = new DefaultTable<RepairDockVm>();
        public DefaultTable<EquipmentDockVm> EquipmentDock { get; } = new DefaultTable<EquipmentDockVm>();
        public readonly VmSession Session;

        public VmDock(VmSession _)
        {
            Session = _;

            _disposable.Add(_.Session.Api_Api_InitGame.Subscribe(OnGameInit));

            _disposable.Add(_.Session.Api_Boat_Repair.Subscribe(p => p.Item2.repairDockVo.ForEach(UpdateDock)));
            _disposable.Add(_.Session.Api_Boat_RepairComplete.Subscribe(p => p.Item2.repairDockVo.ForEach(UpdateDock)));
            _disposable.Add(_.Session.Api_Boat_InstantRepair.Subscribe(p => p.Item2.repairDockVo.ForEach(UpdateDock)));
            _disposable.Add(_.Session.Api_Dock_BuildBoat.Subscribe(p => p.Item2.dockVo.ForEach(UpdateDock)));
            _disposable.Add(_.Session.Api_Dock_BuildEquipment.Subscribe(p => p.Item2.equipmentDockVo.ForEach(UpdateDock)));
            _disposable.Add(_.Session.Api_Dock_GetBoat.Subscribe(p => p.Item2.dockVo.ForEach(UpdateDock)));
            _disposable.Add(_.Session.Api_Dock_GetEquipment.Subscribe(p => p.Item2.equipmentDockVo.ForEach(UpdateDock)));
            _disposable.Add(_.Session.Api_Dock_InstantBuild.Subscribe(p => p.Item2.dockVo.ForEach(UpdateDock)));
            _disposable.Add(_.Session.Api_Dock_InstantEquipmentBuild.Subscribe(p => p.Item2.equipmentDockVo.ForEach(UpdateDock)));
        }

        private void OnGameInit(Tuple<Protocol.Request.Api.InitGame, Protocol.Response.Api.InitGame> p)
        {





            p.Item2.dockVo.ForEach(UpdateDock);
            p.Item2.repairDockVo.ForEach(UpdateDock);
            p.Item2.equipmentDockVo.ForEach(UpdateDock);

        }

        private void UpdateDock(Vo.BuildDock vo)
        {
            var dock = BuildDock[vo.id];
            if(dock != null) {
                dock.Vo = vo;

Changes to WarshipGirlsRSniffer/Vo/Constants.cs.

28
29
30
31
32
33
34
35







        SS = 14,
        SM = 15,
        AP = 16,
        Fortress = 17,
        Airfield = 18,
        Port = 19
    }
}














|
>
>
>
>
>
>
>
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
        SS = 14,
        SM = 15,
        AP = 16,
        Fortress = 17,
        Airfield = 18,
        Port = 19
    }

    public enum BuildShipType : byte
    {
        Unknown = 0,
        Destroyer = 1,
        Cruiser = 2
    }
}

Changes to WarshipGirlsRSniffer/WarshipGirlsRSniffer.csproj.

206
207
208
209
210
211
212

213



214
215
216
217
218
219
220
      <DependentUpon>ProgressBar.xaml</DependentUpon>
    </Compile>
    <Compile Include="View\Controls\ShipStatus.xaml.cs">
      <DependentUpon>ShipStatus.xaml</DependentUpon>
    </Compile>
    <Compile Include="View\Converter\ShipResourceToFillBrushConverter.cs" />
    <Compile Include="View\Converter\HpToFillBrushConverter.cs" />

    <Compile Include="View\Converter\ShipTypeToDescriptionConverter.cs" />



    <Compile Include="View\Equipments.xaml.cs">
      <DependentUpon>Equipments.xaml</DependentUpon>
    </Compile>
    <Compile Include="View\Fleets.xaml.cs">
      <DependentUpon>Fleets.xaml</DependentUpon>
    </Compile>
    <Compile Include="View\Ships.xaml.cs">







>

>
>
>







206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
      <DependentUpon>ProgressBar.xaml</DependentUpon>
    </Compile>
    <Compile Include="View\Controls\ShipStatus.xaml.cs">
      <DependentUpon>ShipStatus.xaml</DependentUpon>
    </Compile>
    <Compile Include="View\Converter\ShipResourceToFillBrushConverter.cs" />
    <Compile Include="View\Converter\HpToFillBrushConverter.cs" />
    <Compile Include="View\Converter\BuildShipTypeToDescriptionConverter.cs" />
    <Compile Include="View\Converter\ShipTypeToDescriptionConverter.cs" />
    <Compile Include="View\Docks.xaml.cs">
      <DependentUpon>Docks.xaml</DependentUpon>
    </Compile>
    <Compile Include="View\Equipments.xaml.cs">
      <DependentUpon>Equipments.xaml</DependentUpon>
    </Compile>
    <Compile Include="View\Fleets.xaml.cs">
      <DependentUpon>Fleets.xaml</DependentUpon>
    </Compile>
    <Compile Include="View\Ships.xaml.cs">
254
255
256
257
258
259
260




261
262
263
264
265
266
267
      <SubType>Designer</SubType>
    </Page>
    <Page Include="View\Controls\ProgressBar.xaml">
      <SubType>Designer</SubType>
      <Generator>MSBuild:Compile</Generator>
    </Page>
    <Page Include="View\Controls\ShipStatus.xaml">




      <SubType>Designer</SubType>
      <Generator>MSBuild:Compile</Generator>
    </Page>
    <Page Include="View\Equipments.xaml">
      <SubType>Designer</SubType>
      <Generator>MSBuild:Compile</Generator>
    </Page>







>
>
>
>







258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
      <SubType>Designer</SubType>
    </Page>
    <Page Include="View\Controls\ProgressBar.xaml">
      <SubType>Designer</SubType>
      <Generator>MSBuild:Compile</Generator>
    </Page>
    <Page Include="View\Controls\ShipStatus.xaml">
      <SubType>Designer</SubType>
      <Generator>MSBuild:Compile</Generator>
    </Page>
    <Page Include="View\Docks.xaml">
      <SubType>Designer</SubType>
      <Generator>MSBuild:Compile</Generator>
    </Page>
    <Page Include="View\Equipments.xaml">
      <SubType>Designer</SubType>
      <Generator>MSBuild:Compile</Generator>
    </Page>