Skip to content

Commit

Permalink
Added Unity Package Exporter
Browse files Browse the repository at this point in the history
  • Loading branch information
Lachee committed Oct 8, 2018
1 parent 60cd225 commit 67ba1a9
Show file tree
Hide file tree
Showing 4 changed files with 249 additions and 0 deletions.
25 changes: 25 additions & 0 deletions UnityPackageExporter.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27130.2027
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnityPackageExporter", "UnityPackageExporter\UnityPackageExporter.csproj", "{1A0EBBC7-063E-4818-94D2-2B2F31C778E5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1A0EBBC7-063E-4818-94D2-2B2F31C778E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1A0EBBC7-063E-4818-94D2-2B2F31C778E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1A0EBBC7-063E-4818-94D2-2B2F31C778E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1A0EBBC7-063E-4818-94D2-2B2F31C778E5}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A0422A7A-CD52-4E7C-BB24-59A5926BA52A}
EndGlobalSection
EndGlobal
212 changes: 212 additions & 0 deletions UnityPackageExporter/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
using ICSharpCode.SharpZipLib.GZip;
using ICSharpCode.SharpZipLib.Tar;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;

namespace UnityPackageExporter
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(">>>> Unity Package Exporter by Lachee");

string unityProject = null;
string output = "package.unitypackage";

List<string> assets = new List<string>();
List<string> directories = new List<string>();

for (int i = 0; i < args.Length; i++)
{
switch (args[i])
{
case "-output":
output = args[++i];
break;

case "-project":
unityProject = args[++i];
break;

case "-asset":
assets.Add(args[++i]);
break;

case "-assets":
assets.AddRange(args[++i].Split(','));
break;

case "-dir":
directories.Add(args[++i]);
break;

case "-dirs":
directories.AddRange(args[++i].Split(','));
break;

default:
Console.WriteLine("Unkown Argument: {0}", args[i]);
break;
}
}

if (string.IsNullOrEmpty(unityProject))
{
Console.WriteLine("-project is null or empty!");
return;
}

if (assets.Count == 0 && directories.Count == 0)
{
Console.WriteLine("No assets or directories supplied");
return;
}

Console.WriteLine("Packing....");
var stopwatch = new Stopwatch();
stopwatch.Start();
{
var files = directories
.SelectMany(dir => Directory.GetFiles(Path.Combine(unityProject, dir), "*", SearchOption.AllDirectories))
.Union(assets)
.Where(f => Path.GetExtension(f) != ".meta");

PackAssets(output, unityProject, files);
}
stopwatch.Stop();

Console.WriteLine("Finished packing. Took {0}ms", stopwatch.ElapsedMilliseconds);
}

public static void PackAssets(string packageOutput, string unityProjectRoot, IEnumerable<string> assets, bool overwrite = true)
{
Console.WriteLine("Packing Project '{0}'", unityProjectRoot);

//Create all the streams
using (var fileStream = new FileStream(packageOutput, FileMode.Create))
{
using (var gzoStream = new GZipOutputStream(fileStream))
using (var tarStream = new TarOutputStream(gzoStream))
{
//Go over every asset, adding it
foreach(var asset in assets)
{
PackUnityAsset(tarStream, unityProjectRoot, asset);
}
}
}
}

private static void PackUnityAsset(TarOutputStream tarStream, string unityProjectRoot, string assetFile)
{
//If the file doesnt exist, skip it
if (!File.Exists(assetFile))
{
Console.WriteLine("SKIP: " + assetFile);
return;
}

//Get all the paths
string relativePath = Path.GetRelativePath(unityProjectRoot, assetFile);
string metaFile = $"{assetFile}.meta";

//If the file doesnt have a meta then skip it
if (!File.Exists(metaFile))
{
Console.WriteLine("SKIP: " + metaFile);
return;
}

//Add the file
Console.WriteLine("ADD: " + relativePath);

//Get the meta contents and the guid from it. We will directly write this to save some write steps
string metaContents = File.ReadAllText(metaFile);

//Get the GUID from a quick substring
int guidIndex = metaContents.IndexOf("guid: ");
string guid = metaContents.Substring(guidIndex + 6, 32);

//Add the asset, meta and pathname.
tarStream.WriteFile(assetFile, $"{guid}/asset");
tarStream.WriteAllText($"{guid}/asset.meta", metaContents);
tarStream.WriteAllText($"{guid}/pathname", relativePath.Replace('\\', '/'));
}

}

public static class TarOutputExtensions
{
public static void WriteFile(this TarOutputStream stream, string source, string dest)
{
using (Stream inputStream = File.OpenRead(source))
{
long fileSize = inputStream.Length;

// Create a tar entry named as appropriate. You can set the name to anything,
// but avoid names starting with drive or UNC.
TarEntry entry = TarEntry.CreateTarEntry(dest);

// Must set size, otherwise TarOutputStream will fail when output exceeds.
entry.Size = fileSize;

// Add the entry to the tar stream, before writing the data.
stream.PutNextEntry(entry);

// this is copied from TarArchive.WriteEntryCore
byte[] localBuffer = new byte[32 * 1024];
while (true)
{
int numRead = inputStream.Read(localBuffer, 0, localBuffer.Length);
if (numRead <= 0)
break;

stream.Write(localBuffer, 0, numRead);
}

//Close the entry
stream.CloseEntry();
}
}

public static void WriteAllText(this TarOutputStream stream, string dest, string content)
{
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(content);

TarEntry entry = TarEntry.CreateTarEntry(dest);
entry.Size = bytes.Length;

// Add the entry to the tar stream, before writing the data.
stream.PutNextEntry(entry);

// this is copied from TarArchive.WriteEntryCore
stream.Write(bytes, 0, bytes.Length);

//Close the entry
stream.CloseEntry();
}
}
}

#if DONTDOTHIS
using (var gzoStream = new GZipOutputStream(outStream))
{
using (var tarArchive = TarArchive.CreateOutputTarArchive(gzoStream))
{
var assetEntry = TarEntry.CreateEntryFromFile(assetFile);
assetEntry.Name = $"{guid}/asset";
tarArchive.WriteEntry(assetEntry, true);

var metaEntry = TarEntry.CreateEntryFromFile(metaFile);
metaEntry.Name = $"{guid}/asset.meta";
tarArchive.WriteEntry(metaEntry, true);

AddTextFile(tarArchive, $"{guid}/pathname", "test.png");
}
}
#endif
12 changes: 12 additions & 0 deletions UnityPackageExporter/UnityPackageExporter.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="SharpZipLib" Version="1.0.0" />
</ItemGroup>

</Project>
Binary file added UnityPackageExporter/package.unitypackage
Binary file not shown.

0 comments on commit 67ba1a9

Please sign in to comment.