Skip to content

Instantly share code, notes, and snippets.

@rdbahm
Last active November 25, 2020 17:06
Show Gist options
  • Select an option

  • Save rdbahm/5840bab0750087e754df92c73980803f to your computer and use it in GitHub Desktop.

Select an option

Save rdbahm/5840bab0750087e754df92c73980803f to your computer and use it in GitHub Desktop.

Image File to Avorion Ship Converter

Okay, so you want to import an arbitrary image into Avorion. You've come to the right place.

This takes a file and spits out a ship. The output from the script will be the same number of blocks wide and tall as the original image has pixels - so you need to resize your image BEFORE importing. I recommend keeping it to 100x200 or under. The XML file is output to the same folder and filename as the image, but with an XML extension.

  1. Make an image of the size you want. The converter leaves the pixels alone - it just deals with conversion from image to Avorion, and it doesn't care how large your image is.
  2. Save a copy of this script somewhere (choose "Download ZIP" then extract it somewhere useful). Open that folder, choose "File", then "Open Windows PowerShell"
  3. (One time only) Run this command to allow you to run custom scripts: set-executionpolicy unrestricted (This has security implications - do your own research before proceeding)
  4. Type: get-help .\Convert-ImageToAvorionShip.ps1 and press enter to see the options.
  5. Type .\Convert-ImageToAvorionShip.ps1 -ImagePath "C:\Path\To\Image.jpg" -BlockWidth 6 to make the XML file
  6. Copy the output file to your ships directory.
  7. Once you have exported the ship, you should load it up in Avorion in a "Creative" mode map on a ship you don't care about. Once loaded, use the "Merge Blocks" function to merge adjacent blocks of the same color. This helps reduce the size substantially, especially in pixel art-type images. Save the ship to disk and use "Copy to Clipboard" to import it into your ship design.
<#
.SYNOPSIS
Generate an Avorion-format XML ship file of an image.
.DESCRIPTION
From an image file (BMP and PNG tested, others should work), generate a simple grid of "pixels" made of blocks in Avorion. This is a very naiive approach and the game doesn't love huge images. I wouldn't recommend anything over 100x200 pixels in size. Once you have your XML file, move it to your "ships" folder, load it up in Avorion, and merge the blocks together, THEN use Avorion's clipboard to add it to your ship of choice.
.PARAMETER ImagePath
One or more paths to images. Transparency is supported by the converter, but Avorion only shows opacity on certain block types, like hologram.
.PARAMETER BlockWidth
Width, in blocks, of the output to Avorion.
.PARAMETER BlockDepth
Thickness, in blocks, of the entire "image" to be exported.
.PARAMETER Material
Name of the material to make the image out of. Trinium is recommended.
.PARAMETER BlockIndex
Which type of block to create. See https://www.reddit.com/r/avorion/comments/60a8dh/ship_xml_index_systems_relations/ for a partial list of possible block indexces. Blank Hull (2) recommended. You can't use certain block types, like "Hologram," since they don't count as real blocks.
.PARAMETER LookIndex
Specifies which direction the block "looks." You probably don't need to change this.
.PARAMETER UpIndex
Specifies which direction on the block is "up." You probably don't need to change this.
.NOTES
If you want to use "hologram" so you can get that sweet, sweet opacity support, import as a block type or material type you aren't otherwise using, attach it to your ship, then change it to hologram in-game.
Inspiration drawn from:
https://gist.github.com/someshinyobject/617bf00556bc43af87cd
https://stackoverflow.com/questions/46614133/get-color-palette-of-image-using-powershell
#>
Param (
[Parameter(Mandatory=$True)]
[ValidateScript({
$_ | ForEach-Object {
Test-Path $_
}
})][String[]]$ImagePath,
[Parameter(Mandatory=$True)]
[Float]$BlockWidth,
[Parameter(Mandatory=$False)]
[Float]$BlockDepth = 0.5,
[ValidateSet("Iron","Titanium","Naonite","Trinium","Xanion","Ogonite","Avorion")]
[String]$Material = "Trinium",
[ValidateRange(1,1024)]
[Int]$BlockIndex = 2,
[ValidateRange(0,5)]
[Int]$LookIndex = 1,
[ValidateRange(0,5)]
[Int]$UpIndex = 3
)
Begin
{
Add-Type -Assembly System.Drawing
$MaterialHT = @{"Iron" = 0;"Titanium" = 1;"Naonite" = 2;"Trinium" = 3;"Xanion" = 5;"Ogonite" = 6;"Avorion" = 7}
$MaterialIndex = $MaterialHT[$Material]
}
Process
{
ForEach ($Image in $ImagePath)
{
$Bitmap = [System.Drawing.Image]::FromFile($Image)
$Path = (Resolve-Path $Image).Path
$Dot = $Path.LastIndexOf(".")
$OutputXmlPath = $Path.Substring(0,$Dot) + ".xml"
#Initialize our XML
[xml]$Doc = New-Object System.Xml.XmlDocument
$dec = $Doc.CreateXmlDeclaration("1.0","UTF-8",$null)
$null = $doc.AppendChild($dec)
$root = $doc.CreateNode("element","ship_design",$null)
$null = $doc.AppendChild($root)
$plan = $doc.CreateNode("element","plan",$null)
$null = $plan.SetAttribute("accumulateHealth","true")
$null = $plan.SetAttribute("convex","false")
$null = $root.AppendChild($plan)
$LastRowParentIndex = -1
$LastBlockIndex = -1
$EachBlockWidth = $BlockWidth/$Bitmap.Width
$AvorionStartX = ($EachBlockWidth/2) * -1
$AvorionStartY = ($EachBlockWidth/2) * -1
$AvorionStartZ = ($BlockDepth/2) * -1
#This segment based on code from https://stackoverflow.com/questions/46614133/get-color-palette-of-image-using-powershell
$BlockZStart = $AvorionStartZ
$BlockZEnd = $AvorionStartZ + ($BlockDepth)
Foreach($y in (0..($Bitmap.Height-1)))
{
$BlockYStart = $AvorionStartY - (($y)*$EachBlockWidth)
$BlockYEnd = $AvorionStartY - (($y-1)*$EachBlockWidth)
Foreach($x in (0..($Bitmap.Width-1)))
{
$Pixel = $Bitmap.GetPixel($X,$Y)
$Opacity = $Pixel | select -ExpandProperty A
$R = $Pixel | select -ExpandProperty R
$G = $Pixel | select -ExpandProperty G
$B = $Pixel | select -ExpandProperty B
$rgbstring = ('{0:x2}{1:x2}{2:x2}{3:x2}' -f $Opacity, $R,$G,$B)
$Item = $Doc.CreateNode("element","item",$null)
$ThisBlockIndex = $LastBlockIndex + 1
if($x -eq 0)
{
$Parent = $LastRowParentIndex
$LastRowParentIndex = $ThisBlockIndex
}
else
{
$Parent = $LastBlockIndex
}
$LastBlockIndex = $ThisBlockIndex
$null = $Item.SetAttribute('parent',$Parent)
$null = $Item.SetAttribute('index',$ThisBlockIndex)
$null = $Plan.AppendChild($Item)
$BlockXStart = $AvorionStartX + (($x)*$EachBlockWidth)
$BlockXEnd = $AvorionStartX + (($x-1)*$EachBlockWidth)
$null = $Block = $Doc.CreateNode("element","block",$null)
$null = $Block.SetAttribute('lx',$BlockXStart)
$null = $Block.SetAttribute('ly',$BlockYStart)
$null = $Block.SetAttribute('lz',$BlockZStart)
$null = $Block.SetAttribute('ux',$BlockXEnd)
$null = $Block.SetAttribute('uy',$BlockYEnd)
$null = $Block.SetAttribute('uz',$BlockZEnd)
$null = $Block.SetAttribute('index',$BlockIndex)
$null = $Block.SetAttribute('material',$MaterialIndex)
$null = $Block.SetAttribute('look',$LookIndex)
$null = $Block.SetAttribute('up',$UpIndex)
$null = $Block.SetAttribute('color',$rgbstring)
$null = $Item.AppendChild($Block)
}
}
$utf8WithoutBom = New-Object System.Text.UTF8Encoding($false)
$sw = New-Object System.IO.StreamWriter($OutputXmlPath, $false, $utf8WithoutBom)
$Doc.Save($sw)
$sw.Close()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment