Created
July 26, 2022 06:49
-
-
Save dend/9cad0906bc5e1cb82c8c93962c324578 to your computer and use it in GitHub Desktop.
Script to enable all Halo Infinite content (maps and game modes) for your account
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Script by Den Delimarsky - Written in July 2022 | |
# Enables all modes and maps that are available in a given build manifest. | |
# For details, refer to https://den.dev/blog/halo-infinite-enable-all-content | |
param ( | |
# Spartan V4 token, used for authentication against the Halo Infinite API. | |
[Parameter(Mandatory=$true)] | |
[string]$SpartanV4Token, | |
# Build ID accessible to the user which is authenticating. | |
[Parameter(Mandatory=$true)] | |
[string]$BuildId, | |
# User XUID used for inclusion in the binary blob | |
[Parameter(Mandatory=$true)] | |
[string]$Xuid | |
) | |
function ProcessAsset([Guid]$AssetId, [Guid]$AssetVersionId, [string]$AssetName) { | |
Write-Host "Processing asset with version ${AssetId} and version ${AssetVersionId}" | |
Write-Host "Asset name:" $AssetName | |
$reverseAssetGuid = $assetId.ToByteArray() | |
$reverseVersionGuid = $versionId.ToByteArray() | |
$properAssetId = [RequestData.Helper]::GetRawGuid($reverseAssetGuid) | |
$properVersionId = [RequestData.Helper]::GetRawGuid($reverseVersionGuid) | |
$entity = [RequestData.Entity]::new() | |
$entity.Admin = $Xuid | |
$entity.Dummy = [RequestData.DummyEntity]::new() | |
$entity.AssetDefinition = New-Object System.Collections.Generic.List[RequestData.Asset] | |
$asset = [RequestData.Asset]::new() | |
$asset.AssetId = $properAssetId | |
$asset.AssetVersion = $properVersionId | |
$entity.AssetDefinition.Add($asset) | |
$entity.Metadata = New-Object System.Collections.Generic.List[string] | |
$entity.Metadata.Add($AssetName) | |
Write-Host "Writing data to file..." | |
[RequestData.Helper]::WriteToFile($entity) | |
} | |
# Only download a new NuGet binary if one doesn't already exist in the current folder. | |
if (-Not(Test-Path nuget.exe -PathType Leaf)) { | |
Write-Host "Downloading NuGet (PowerShell package management is messy)..." | |
Invoke-WebRequest https://dist.nuget.org/win-x86-commandline/latest/nuget.exe -OutFile nuget.exe | |
} else { | |
Write-Host "NuGet.exe already exists in current folder." | |
} | |
Write-Host "Installing the Microsoft Bond helper package..." | |
.\nuget.exe install Bond.Core.CSharp -OutputDirectory . -Version 9.0.5 | |
# Loading the Bond assembly, that will be necessary to serialize the data | |
$bondLibaryPath = Resolve-Path ".\Bond.Core.CSharp.9.0.5\lib\net46\Bond.dll" | |
$bondAttributesLibaryPath = Resolve-Path ".\Bond.Core.CSharp.9.0.5\lib\net46\Bond.Attributes.dll" | |
$bondIOLibaryPath = Resolve-Path ".\Bond.Core.CSharp.9.0.5\lib\net46\Bond.IO.dll" | |
$bondReflectionLibaryPath = Resolve-Path ".\Bond.Core.CSharp.9.0.5\lib\net46\Bond.Reflection.dll" | |
[String[]]$paths = $bondLibaryPath, $bondAttributesLibaryPath, $bondIOLibaryPath, $bondReflectionLibaryPath | |
Add-Type -Path $bondLibaryPath | |
Add-Type -Path $bondAttributesLibaryPath | |
Add-Type -Path $bondIOLibaryPath | |
Add-Type -Path $bondReflectionLibaryPath | |
Write-Host $paths | |
$entityDefinition = @" | |
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq; | |
using Bond; | |
using Bond.Protocols; | |
using Bond.Tag; | |
namespace RequestData | |
{ | |
[Bond.Schema] | |
public class Entity | |
{ | |
[Bond.Id(0), Bond.Type(typeof(wstring))] | |
public string Admin { get; set; } | |
[Bond.Id(1), Bond.Type(typeof(Bond.Tag.structT))] | |
public DummyEntity Dummy { get; set; } | |
[Bond.Id(2)] | |
public List<Asset> AssetDefinition { get; set; } | |
[Bond.Id(6), Bond.Type(typeof(List<Bond.Tag.wstring>))] | |
public List<string> Metadata { get; set; } | |
} | |
[Bond.Schema] | |
public class DummyEntity | |
{ | |
} | |
[Bond.Schema] | |
public class Asset | |
{ | |
[Bond.Id(0)] | |
public RawGuidDefinition AssetId { get; set; } | |
[Bond.Id(1)] | |
public RawGuidDefinition AssetVersion { get; set; } | |
} | |
[Bond.Schema] | |
public class RawGuidDefinition | |
{ | |
[Bond.Id(0)] | |
public UInt32 FragmentA { get; set; } | |
[Bond.Id(1)] | |
public UInt16 FragmentB { get; set; } | |
[Bond.Id(2)] | |
public UInt16 FragmentC { get; set; } | |
[Bond.Id(3)] | |
public UInt64 FragmentD { get; set; } | |
} | |
public static class Helper | |
{ | |
public static RawGuidDefinition GetRawGuid(byte[] data) | |
{ | |
return new RawGuidDefinition() | |
{ | |
FragmentA = BitConverter.ToUInt32(data.Take(4).ToArray(), 0), | |
FragmentB = BitConverter.ToUInt16(data.Skip(4).Take(2).ToArray(), 0), | |
FragmentC = BitConverter.ToUInt16(data.Skip(6).Take(2).ToArray(), 0), | |
FragmentD = BitConverter.ToUInt64(data.Skip(8).Take(8).ToArray(), 0) | |
}; | |
} | |
public static void WriteToFile(Entity entity) | |
{ | |
using (var stream = new FileStream("example.bin", FileMode.Create)) | |
{ | |
var output = new Bond.IO.Unsafe.OutputStream(stream); | |
CompactBinaryWriter<Bond.IO.Unsafe.OutputBuffer> writer = new Bond.Protocols.CompactBinaryWriter<Bond.IO.Unsafe.OutputBuffer>(output, 2); | |
Serialize.To(writer, entity); | |
output.Flush(); | |
} | |
} | |
} | |
} | |
"@ | |
Try { | |
Add-Type -TypeDefinition $entityDefinition -ReferencedAssemblies $paths | |
} Catch { | |
Write-Host "Looks like the type is already loaded." | |
} | |
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]" | |
$headers.Add("X-343-Authorization-Spartan", $SpartanV4Token) | |
$headers.Add("Accept", "application/json") | |
# Try and get build metadata. | |
Try { | |
$url = "https://discovery-infiniteugc.svc.halowaypoint.com/hi/manifests/builds/${buildId}/game" | |
Write-Host "Trying to work with the following URL:" $url | |
$response = Invoke-RestMethod $url -Method 'GET' -Headers $headers | |
$gameVariants = $response.UgcGameVariantLinks | |
$maps = $response.MapLinks | |
Write-Host "Response contains $($maps.Count) map links and $($gameVariants.Count) game variants." | |
# Process game variant links | |
$counter = 1 | |
foreach($gameVariant in $gameVariants){ | |
$assetId = [Guid]::new($gameVariant.AssetId) | |
$versionId = [Guid]::new($gameVariant.VersionId) | |
ProcessAsset $assetId $versionId $gameVariant.PublicName | |
Write-Host "Preparing to store..." | |
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]" | |
$headers.Add("X-343-Authorization-Spartan", $SpartanV4Token) | |
$headers.Add("Accept", "application/json") | |
$headers.Add("Content-Type", "application/x-bond-compact-binary") | |
$body = [System.IO.File]::ReadAllBytes('example.bin') | |
$fullPath = [System.IO.Path]::GetFullPath('example.bin') | |
Write-Host $fullPath | |
$response = Invoke-WebRequest 'https://authoring-infiniteugc.svc.halowaypoint.com/hi/UgcGameVariants' -Method 'POST' -Headers $headers -Body $body | |
Write-Host "[${counter}] Storage routine ended with HTTP status code" $response.StatusCode | |
$counter = $counter + 1 | |
} | |
Write-Host "Going to be processing map links..." | |
$counter = 1 | |
foreach($map in $maps){ | |
$assetId = [Guid]::new($map.AssetId) | |
$versionId = [Guid]::new($map.VersionId) | |
ProcessAsset $assetId $versionId $map.PublicName | |
Write-Host "Preparing to store..." | |
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]" | |
$headers.Add("X-343-Authorization-Spartan", $SpartanV4Token) | |
$headers.Add("Accept", "application/json") | |
$headers.Add("Content-Type", "application/x-bond-compact-binary") | |
$body = [System.IO.File]::ReadAllBytes('example.bin') | |
$fullPath = [System.IO.Path]::GetFullPath('example.bin') | |
Write-Host $fullPath | |
$response = Invoke-WebRequest 'https://authoring-infiniteugc.svc.halowaypoint.com/hi/maps' -Method 'POST' -Headers $headers -Body $body | |
Write-Host "[${counter}] Storage routine ended with HTTP status code" $response.StatusCode | |
$counter = $counter + 1 | |
} | |
} Catch { | |
Write-Host "Error processing build metadata." | |
Write-Warning $Error[0] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment