chore: Adds responsiveness to Packet Documentation (#2304)
This commit is contained in:
parent
a9e611d46a
commit
efe385a176
5 changed files with 346 additions and 120 deletions
|
|
@ -113,70 +113,6 @@
|
|||
"line": 27
|
||||
},
|
||||
"notes": "High Seas expansion only. Entities include mobiles and items on the boat. Coordinates include the boat\u0027s movement offset."
|
||||
},
|
||||
{
|
||||
"id": "0xF7",
|
||||
"name": "Packet Container",
|
||||
"description": "Container packet for batching multiple entity packets. Used for efficient display of boats and other groups of entities.",
|
||||
"direction": "outgoing",
|
||||
"isDynamic": true,
|
||||
"size": "5+",
|
||||
"fields": [
|
||||
{
|
||||
"name": "Packet ID",
|
||||
"type": "byte",
|
||||
"size": 1,
|
||||
"value": "0xF7",
|
||||
"description": "Packet identifier"
|
||||
},
|
||||
{
|
||||
"name": "Length",
|
||||
"type": "ushort",
|
||||
"size": 2,
|
||||
"description": "Total packet length"
|
||||
},
|
||||
{
|
||||
"name": "Packet Count",
|
||||
"type": "ushort",
|
||||
"size": 2,
|
||||
"description": "Number of embedded packets"
|
||||
},
|
||||
{
|
||||
"name": "Packets",
|
||||
"type": "array",
|
||||
"description": "Embedded packets (typically 0xF3 World Entity packets)",
|
||||
"loop": {
|
||||
"countField": "packetCount",
|
||||
"fields": [
|
||||
{
|
||||
"name": "Embedded Packet",
|
||||
"type": "packet",
|
||||
"description": "Complete embedded packet (0xF3 World Entity or similar)"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"related": [
|
||||
{
|
||||
"id": "0xF3",
|
||||
"relationship": "contains",
|
||||
"note": "Typically contains World Entity packets"
|
||||
},
|
||||
{
|
||||
"id": "0xF6",
|
||||
"relationship": "variant",
|
||||
"note": "Used alongside Move Boat HS for boat display"
|
||||
}
|
||||
],
|
||||
"clientVersion": {
|
||||
"feature": "HighSeas"
|
||||
},
|
||||
"notes": "Uses PacketContainerBuilder for dynamic growth when embedding many packets. Minimum packet length is 5 bytes (header only).",
|
||||
"source": {
|
||||
"file": "Projects/Server/Network/Packets/PacketContainerBuilder.cs",
|
||||
"line": 23
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -522,6 +522,7 @@
|
|||
"name": "Packet Container",
|
||||
"description": "Container packet for batching multiple entity packets. Used for sending groups of related entities efficiently, such as all items and mobiles visible on a boat.",
|
||||
"direction": "outgoing",
|
||||
"tags": ["Boat"],
|
||||
"isDynamic": true,
|
||||
"size": "5+",
|
||||
"fields": [
|
||||
|
|
@ -566,16 +567,20 @@
|
|||
"id": "0xF3",
|
||||
"relationship": "contains",
|
||||
"note": "Typically contains World Entity packets"
|
||||
},
|
||||
{
|
||||
"id": "0xF6",
|
||||
"relationship": "variant",
|
||||
"note": "Used alongside Move Boat HS for boat display"
|
||||
}
|
||||
],
|
||||
"clientVersion": {
|
||||
"min": "7.0.0.0",
|
||||
"feature": "StygianAbyss"
|
||||
"feature": "HighSeas"
|
||||
},
|
||||
"notes": "Uses PacketContainerBuilder for efficient dynamic growth. Commonly used by boat system to batch all visible entities on deck.",
|
||||
"notes": "Uses PacketContainerBuilder for efficient dynamic growth. Commonly used by boat system to batch all visible entities on deck. Minimum packet length is 5 bytes (header only).",
|
||||
"source": {
|
||||
"file": "Projects/Server/Network/Packets/PacketContainerBuilder.cs",
|
||||
"line": 9
|
||||
"line": 23
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -77,21 +77,24 @@
|
|||
<body class="bg-modern-dark-black text-gold-300 font-sans h-screen overflow-hidden">
|
||||
<div id="app" class="h-screen flex flex-col">
|
||||
<!-- Header -->
|
||||
<header class="bg-modern-black p-4 shadow-lg border-b border-gold-500/30">
|
||||
<div class="max-w-7xl mx-auto flex items-center justify-between">
|
||||
<div class="flex items-center space-x-4">
|
||||
<img src="https://modernuo.com/branding/logo.svg" class="h-12 w-12">
|
||||
<div>
|
||||
<h1 class="text-white text-xl font-medium">ModernUO Packet Documentation</h1>
|
||||
<p class="text-gold-500/70 text-sm">Ultima Online Network Protocol Reference</p>
|
||||
<header class="bg-modern-black p-3 md:p-4 shadow-lg border-b border-gold-500/30">
|
||||
<div class="max-w-7xl mx-auto flex items-center justify-between gap-2">
|
||||
<div class="flex items-center space-x-2 md:space-x-4 min-w-0">
|
||||
<img src="https://modernuo.com/branding/logo.svg" class="h-8 w-8 md:h-12 md:w-12 flex-shrink-0">
|
||||
<div class="min-w-0">
|
||||
<h1 class="text-white text-base md:text-xl font-medium">
|
||||
<span class="md:hidden">Packet Documentation</span>
|
||||
<span class="hidden md:inline">ModernUO Packet Documentation</span>
|
||||
</h1>
|
||||
<p class="text-gold-500/70 text-xs md:text-sm hidden sm:block">Ultima Online Network Protocol Reference</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center space-x-4">
|
||||
<button id="typeLegendBtn" class="px-3 py-1.5 text-sm bg-modern-dark-black text-gold-400 rounded border border-gold-500/30 hover:border-gold-500 hover:bg-gold-500/10 transition-colors flex items-center space-x-1.5">
|
||||
<div class="flex items-center space-x-2 md:space-x-4 flex-shrink-0">
|
||||
<button id="typeLegendBtn" class="px-2 md:px-3 py-1.5 text-sm bg-modern-dark-black text-gold-400 rounded border border-gold-500/30 hover:border-gold-500 hover:bg-gold-500/10 transition-colors flex items-center space-x-1.5">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
|
||||
<span>Types</span>
|
||||
<span class="hidden sm:inline">Types</span>
|
||||
</button>
|
||||
<span id="packetCount" class="text-gold-500/70 text-sm"></span>
|
||||
<span id="packetCount" class="text-gold-500/70 text-xs md:text-sm whitespace-nowrap"></span>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
|
@ -99,9 +102,15 @@
|
|||
<!-- Main Content -->
|
||||
<div class="flex-1 flex overflow-hidden min-h-0">
|
||||
<!-- Left Panel: Packet List -->
|
||||
<aside id="sidebar" class="w-80 bg-modern-black border-r border-gold-500/30 flex flex-col overflow-hidden">
|
||||
<aside id="sidebar" class="w-full md:w-80 bg-modern-black border-r border-gold-500/30 flex flex-col overflow-hidden">
|
||||
<!-- Search & Filter -->
|
||||
<div class="p-3 border-b border-gold-500/20 space-y-2">
|
||||
<!-- Collapse button for medium screens -->
|
||||
<div class="hidden md:flex xl:hidden justify-end -mt-1 -mr-1 mb-1">
|
||||
<button id="collapseSidebarBtn" class="p-1 text-gold-500/70 hover:text-gold-500 transition-colors" title="Collapse sidebar">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 19l-7-7 7-7m8 14l-7-7 7-7"></path></svg>
|
||||
</button>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
id="searchInput"
|
||||
|
|
@ -115,10 +124,14 @@
|
|||
<button data-filter="both" class="filter-btn flex-1 px-2 py-1 text-xs rounded bg-modern-dark-black text-both border border-both/50 hover:bg-both/20">Both</button>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-gold-500/70 text-xs flex-shrink-0">Tags:</span>
|
||||
<button id="toggleTagsBtn" class="md:hidden text-gold-500/70 text-xs flex items-center gap-1 hover:text-gold-400">
|
||||
<span>Tags</span>
|
||||
<svg id="toggleTagsIcon" class="w-3 h-3 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg>
|
||||
</button>
|
||||
<span class="text-gold-500/70 text-xs flex-shrink-0 hidden md:inline">Tags:</span>
|
||||
<button id="clearTagsBtn" class="text-xs px-2 py-0.5 rounded bg-modern-dark-black text-gold-500/70 border border-gold-500/30 hover:border-gold-500 hover:text-gold-400 hidden">Clear</button>
|
||||
</div>
|
||||
<div id="tagFilter" class="flex flex-wrap gap-1 max-h-32 overflow-y-auto">
|
||||
<div id="tagFilter" class="hidden md:flex flex-wrap gap-1 max-h-32 overflow-y-auto">
|
||||
<!-- Tags will be populated by JavaScript -->
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -129,9 +142,20 @@
|
|||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- Expand sidebar button (shown when collapsed on medium screens) -->
|
||||
<button id="expandSidebarBtn" class="hidden bg-modern-black border-r border-gold-500/30 px-2 py-4 text-gold-500/70 hover:text-gold-500 hover:bg-modern-black-hover transition-colors" title="Expand sidebar">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 5l7 7-7 7M5 5l7 7-7 7"></path></svg>
|
||||
</button>
|
||||
|
||||
<!-- Right Panel: Packet Details -->
|
||||
<main class="flex-1 overflow-y-auto bg-modern-dark-black">
|
||||
<div id="packetDetails" class="p-6 max-w-4xl mx-auto">
|
||||
<main id="detailPanel" class="hidden md:block flex-1 overflow-y-auto bg-modern-dark-black">
|
||||
<div id="packetDetails" class="p-4 md:p-6 max-w-4xl mx-auto">
|
||||
<!-- Mobile back button -->
|
||||
<button id="mobileBackBtn" class="md:hidden flex items-center space-x-2 text-gold-500 hover:text-gold-400 mb-4 -ml-1">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path></svg>
|
||||
<span>Back to list</span>
|
||||
</button>
|
||||
|
||||
<!-- Welcome message when no packet selected -->
|
||||
<div id="welcomeMessage" class="text-center py-16">
|
||||
<div class="text-gold-500/50 text-6xl mb-4">📦</div>
|
||||
|
|
@ -152,9 +176,9 @@
|
|||
</div>
|
||||
<h2 id="detailName" class="text-xl text-gold-500 font-medium"></h2>
|
||||
</div>
|
||||
<a id="sourceLink" href="#" target="_blank" class="flex items-center space-x-1 text-sm text-gold-500/70 hover:text-gold-500 transition-colors">
|
||||
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>
|
||||
<span>View Source</span>
|
||||
<a id="sourceLink" href="#" target="_blank" class="flex items-center space-x-1 text-sm text-gold-500/70 hover:text-gold-500 transition-colors" title="View Source on GitHub">
|
||||
<svg class="w-5 h-5 md:w-4 md:h-4" fill="currentColor" viewBox="0 0 24 24"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>
|
||||
<span class="hidden md:inline">View Source</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
|
@ -183,8 +207,8 @@
|
|||
<!-- Fields Table -->
|
||||
<div id="fieldsSection" class="mb-6">
|
||||
<h3 class="text-gold-500 font-medium mb-3">Packet Structure</h3>
|
||||
<div class="bg-modern-black rounded-lg border border-gold-500/20 overflow-hidden">
|
||||
<table class="w-full text-sm table-fixed">
|
||||
<div class="bg-modern-black rounded-lg border border-gold-500/20 overflow-x-auto">
|
||||
<table class="w-full text-sm table-fixed min-w-[600px]">
|
||||
<thead>
|
||||
<tr class="bg-gold-500/10 text-gold-500">
|
||||
<th class="px-4 py-2 text-left font-medium w-16">Offset</th>
|
||||
|
|
@ -204,8 +228,8 @@
|
|||
<!-- Subpackets (for container packets like 0xBF, 0xD7) -->
|
||||
<div id="subpacketsSection" class="mb-6 hidden">
|
||||
<h3 class="text-gold-500 font-medium mb-3">Subpackets</h3>
|
||||
<div class="bg-modern-black rounded-lg border border-gold-500/20 overflow-hidden">
|
||||
<table class="w-full text-sm">
|
||||
<div class="bg-modern-black rounded-lg border border-gold-500/20 overflow-x-auto">
|
||||
<table class="w-full text-sm min-w-[500px]">
|
||||
<thead>
|
||||
<tr class="bg-gold-500/10 text-gold-500">
|
||||
<th class="px-4 py-2 text-left font-medium w-24">SubID</th>
|
||||
|
|
@ -524,6 +548,106 @@ const packetList = document.getElementById('packetList');
|
|||
const packetCount = document.getElementById('packetCount');
|
||||
const welcomeMessage = document.getElementById('welcomeMessage');
|
||||
const packetContent = document.getElementById('packetContent');
|
||||
const sidebar = document.getElementById('sidebar');
|
||||
const detailPanel = document.getElementById('detailPanel');
|
||||
const mobileBackBtn = document.getElementById('mobileBackBtn');
|
||||
const collapseSidebarBtn = document.getElementById('collapseSidebarBtn');
|
||||
const expandSidebarBtn = document.getElementById('expandSidebarBtn');
|
||||
|
||||
// Responsive breakpoints
|
||||
const MOBILE_BREAKPOINT = 768; // md breakpoint
|
||||
const LARGE_BREAKPOINT = 1280; // xl breakpoint
|
||||
|
||||
function isMobile() {
|
||||
return window.innerWidth < MOBILE_BREAKPOINT;
|
||||
}
|
||||
|
||||
function isMediumScreen() {
|
||||
return window.innerWidth >= MOBILE_BREAKPOINT && window.innerWidth < LARGE_BREAKPOINT;
|
||||
}
|
||||
|
||||
// Sidebar collapse state (for medium screens)
|
||||
let isSidebarCollapsed = false;
|
||||
|
||||
function collapseSidebar() {
|
||||
if (!isMediumScreen()) return;
|
||||
isSidebarCollapsed = true;
|
||||
sidebar.classList.add('hidden');
|
||||
expandSidebarBtn.classList.remove('hidden');
|
||||
}
|
||||
|
||||
function expandSidebar() {
|
||||
isSidebarCollapsed = false;
|
||||
sidebar.classList.remove('hidden');
|
||||
expandSidebarBtn.classList.add('hidden');
|
||||
}
|
||||
|
||||
// Collapse/expand button handlers
|
||||
collapseSidebarBtn.addEventListener('click', collapseSidebar);
|
||||
expandSidebarBtn.addEventListener('click', expandSidebar);
|
||||
|
||||
function showMobileDetailView() {
|
||||
if (!isMobile()) return;
|
||||
sidebar.classList.add('hidden');
|
||||
detailPanel.classList.remove('hidden');
|
||||
}
|
||||
|
||||
function showMobileListView() {
|
||||
if (!isMobile()) return;
|
||||
sidebar.classList.remove('hidden');
|
||||
detailPanel.classList.add('hidden');
|
||||
}
|
||||
|
||||
// Back button handler
|
||||
mobileBackBtn.addEventListener('click', () => {
|
||||
showMobileListView();
|
||||
});
|
||||
|
||||
// Handle window resize - reset to proper state
|
||||
window.addEventListener('resize', () => {
|
||||
if (isMobile()) {
|
||||
// Mobile: hide expand button, handle list/detail toggle
|
||||
expandSidebarBtn.classList.add('hidden');
|
||||
if (!selectedPacket) {
|
||||
sidebar.classList.remove('hidden');
|
||||
detailPanel.classList.add('hidden');
|
||||
}
|
||||
} else if (isMediumScreen()) {
|
||||
// Medium: show both panels, respect collapsed state
|
||||
detailPanel.classList.remove('hidden');
|
||||
if (isSidebarCollapsed) {
|
||||
sidebar.classList.add('hidden');
|
||||
expandSidebarBtn.classList.remove('hidden');
|
||||
} else {
|
||||
sidebar.classList.remove('hidden');
|
||||
expandSidebarBtn.classList.add('hidden');
|
||||
}
|
||||
} else {
|
||||
// Large: always show both panels, no collapse
|
||||
sidebar.classList.remove('hidden');
|
||||
detailPanel.classList.remove('hidden');
|
||||
expandSidebarBtn.classList.add('hidden');
|
||||
isSidebarCollapsed = false;
|
||||
}
|
||||
});
|
||||
|
||||
// Tags toggle for mobile
|
||||
const toggleTagsBtn = document.getElementById('toggleTagsBtn');
|
||||
const toggleTagsIcon = document.getElementById('toggleTagsIcon');
|
||||
let tagsExpanded = false;
|
||||
|
||||
toggleTagsBtn.addEventListener('click', () => {
|
||||
tagsExpanded = !tagsExpanded;
|
||||
if (tagsExpanded) {
|
||||
tagFilterContainer.classList.remove('hidden');
|
||||
tagFilterContainer.classList.add('flex');
|
||||
toggleTagsIcon.style.transform = 'rotate(180deg)';
|
||||
} else {
|
||||
tagFilterContainer.classList.add('hidden');
|
||||
tagFilterContainer.classList.remove('flex');
|
||||
toggleTagsIcon.style.transform = '';
|
||||
}
|
||||
});
|
||||
|
||||
// Helper to ensure tags is always an array
|
||||
function ensureArray(val) {
|
||||
|
|
@ -848,6 +972,9 @@ function renderFields(fields, parentOffset = 0) {
|
|||
function selectPacket(packet) {
|
||||
selectedPacket = packet;
|
||||
|
||||
// Switch to detail view on mobile
|
||||
showMobileDetailView();
|
||||
|
||||
// Update list selection
|
||||
document.querySelectorAll('.packet-item').forEach(el => {
|
||||
const idMatch = el.dataset.id === packet.id && (el.dataset.subid || '') === (packet.subId || '');
|
||||
|
|
@ -1477,7 +1604,13 @@ function loadFromHash() {
|
|||
(!direction || p.direction === direction)
|
||||
);
|
||||
|
||||
if (packet) selectPacket(packet);
|
||||
if (packet) {
|
||||
selectPacket(packet);
|
||||
// Collapse sidebar on medium screens when loading with hash
|
||||
if (isMediumScreen()) {
|
||||
collapseSidebar();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ $outgoingDir = Join-Path $packetsDir "outgoing"
|
|||
|
||||
# Read incoming packets
|
||||
if (Test-Path $incomingDir) {
|
||||
$incomingFiles = Get-ChildItem "$incomingDir\*.json" -ErrorAction SilentlyContinue
|
||||
$incomingFiles = Get-ChildItem "$incomingDir\*.json" -ErrorAction SilentlyContinue | Sort-Object Name
|
||||
foreach ($file in $incomingFiles) {
|
||||
Write-Host " Reading: $($file.Name)" -ForegroundColor Gray
|
||||
try {
|
||||
|
|
@ -88,7 +88,7 @@ if (Test-Path $incomingDir) {
|
|||
|
||||
# Read outgoing packets
|
||||
if (Test-Path $outgoingDir) {
|
||||
$outgoingFiles = Get-ChildItem "$outgoingDir\*.json" -ErrorAction SilentlyContinue
|
||||
$outgoingFiles = Get-ChildItem "$outgoingDir\*.json" -ErrorAction SilentlyContinue | Sort-Object Name
|
||||
foreach ($file in $outgoingFiles) {
|
||||
Write-Host " Reading: $($file.Name)" -ForegroundColor Gray
|
||||
try {
|
||||
|
|
@ -140,6 +140,25 @@ if ($totalPackets -eq 0) {
|
|||
Write-Warning "No packets found! The output will have empty documentation."
|
||||
}
|
||||
|
||||
# Sort packets by ID for deterministic output
|
||||
# Handle IDs like "0x02" and "0xBF/0x05" (split on / and parse first part)
|
||||
$allPackets.incoming = @($allPackets.incoming | Sort-Object {
|
||||
$baseId = $_.id -split '/' | Select-Object -First 1
|
||||
[Convert]::ToInt32($baseId, 16)
|
||||
}, {
|
||||
if ($_.subId) { [Convert]::ToInt32($_.subId, 16) }
|
||||
elseif ($_.id -match '/') { [Convert]::ToInt32(($_.id -split '/' | Select-Object -Last 1), 16) }
|
||||
else { 0 }
|
||||
})
|
||||
$allPackets.outgoing = @($allPackets.outgoing | Sort-Object {
|
||||
$baseId = $_.id -split '/' | Select-Object -First 1
|
||||
[Convert]::ToInt32($baseId, 16)
|
||||
}, {
|
||||
if ($_.subId) { [Convert]::ToInt32($_.subId, 16) }
|
||||
elseif ($_.id -match '/') { [Convert]::ToInt32(($_.id -split '/' | Select-Object -Last 1), 16) }
|
||||
else { 0 }
|
||||
})
|
||||
|
||||
# Convert to JSON
|
||||
$packetsJson = $allPackets | ConvertTo-Json -Depth 20 -Compress
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue