Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

levelshots shader rename support #36

Merged
merged 12 commits into from
Nov 2, 2024
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project>

<PropertyGroup>
<Version>0.1.10</Version>
<Version>1.0.0-rc1</Version>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
Expand Down
2 changes: 1 addition & 1 deletion Pack3r.Console/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
},
"unsung": {
"commandName": "Project",
"commandLineArgs": "\"C:\\Temp\\ET\\map\\ET\\etmain\\maps\\unsung.map\" -d -m etjump_stable"
"commandLineArgs": "\"C:\\Temp\\ET\\map\\ET\\etmain\\maps\\unsung.map\" -d -m etjump_stable -r unsung_t1"
},
"noargs": {
"commandName": "Project",
Expand Down
70 changes: 43 additions & 27 deletions Pack3r.Console/RootCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ namespace Pack3r.Console;

[CliCommand(
Description = "Pack3r, tool to create release-ready pk3s from NetRadiant maps",
NameCasingConvention = CliNameCasingConvention.LowerCase)]
NameCasingConvention = CliNameCasingConvention.LowerCase,
ShortFormAutoGenerate = false)]
public class RootCommand
{
[CliArgument(
Expand All @@ -19,37 +20,40 @@ public class RootCommand
public FileInfo Map { get; set; } = null!;

[CliOption(
Description = "Path to destination pk3 or directory, defaults to etmain",
Description = "Path to destination pk3/zip (or directory where it will be written), defaults to etmain/mapname.pk3",
Required = false,
ValidationRules = CliValidationRules.LegalPath)]
ValidationRules = CliValidationRules.LegalPath,
Aliases = ["-o"])]
public FileSystemInfo? Output { get; set; }

[CliOption(Description = "Discover packed files and estimate file size without creating a pk3")]
[CliOption(
Description = "Discover packed files and estimate file size without creating a pk3",
Aliases = ["-d"])]
public bool DryRun { get; set; }

[CliOption(
Description = "Map release name (bsp, lightmaps, mapscript, etc.)",
Description = "Name of the map after packing (renames bsp, lightmaps, mapscript etc.)",
Required = false,
ValidationRules = CliValidationRules.LegalFileName)]
ValidationRules = CliValidationRules.LegalFileName,
Aliases = ["-r"])]
public string? Rename { get; set; }

[CliOption(
Description = "Log severity threshold",
Arity = CliArgumentArity.ZeroOrOne)]
Arity = CliArgumentArity.ZeroOrOne,
Aliases = ["-v"])]
public LogLevel Verbosity { get; set; } = LogLevel.Info;

[CliOption(Description = "Complete packing even if some files are missing")]
[CliOption(
Description = "Complete packing even if some files are missing",
Aliases = ["-l"])]
public bool Loose { get; set; }

[CliOption(
Description = "Pack source files such as .map, editorimages, misc_models")]
Description = "Pack only source files (.map, editorimages, misc_models) without packing BSP & lightmaps",
Aliases = ["-s"])]
public bool Source { get; set; }

[CliOption(
Description = "Only read shaders present in shaderlist.txt if one exists",
Aliases = ["-sl"])]
public bool Shaderlist { get; set; }

[CliOption(
Description = "Print shader resolution details (Debug verbosity needed)",
Aliases = ["-sd"])]
Expand All @@ -61,26 +65,38 @@ public class RootCommand
public bool ReferenceDebug { get; set; }

[CliOption(
Description = "Overwrite existing files in the output path with impunity")]
Description = "Overwrite existing files in the output path with impunity",
Aliases = ["-f", "--overwrite"])]
public bool Force { get; set; }

[CliOption(
Description = "Include pk3 files and pk3dirs in etmain when indexing files")]
Description = "Include pk3 files and pk3dirs in etmain when indexing files",
Aliases = ["-p", "--pk3"])]
public bool IncludePk3 { get; set; }

[CliOption(
Description = "Ignore some pk3 files or pk3dir directories",
Description = "Don't scan pk3/pk3dirs for assets",
Arity = CliArgumentArity.ZeroOrMore,
ValidationRules = CliValidationRules.LegalPath,
AllowMultipleArgumentsPerToken = true)]
public List<string> Ignore { get; set; } = ["pak1.pk3", "pak2.pk3", "mp_bin.pk3"];
AllowMultipleArgumentsPerToken = true,
Aliases = ["-ns"])]
public List<string> NoScan { get; set; } = ["pak1.pk3", "pak2.pk3", "mp_bin.pk3"];

[CliOption(
Description = "Never pack files found in these pk3s or directories",
Description = "Scan some pk3s/pk3dirs but don't pack their contants",
Arity = CliArgumentArity.ZeroOrMore,
ValidationRules = CliValidationRules.LegalPath,
AllowMultipleArgumentsPerToken = true)]
public List<string> Exclude { get; set; } = ["pak0.pk3", "pak0.pk3dir"];
AllowMultipleArgumentsPerToken = true,
Aliases = ["-np"])]
public List<string> NoPack { get; set; } =
[
"pak0.pk3",
"pak0.pk3dir",
"lights.pk3",
"sd-mapobjects.pk3",
"common.pk3",
"astro-skies.pk3",
];

[CliOption(
Description = "Adds all pk3s in mod directories to exclude-list",
Expand All @@ -96,16 +112,15 @@ public Task<int> RunAsync()
MapFile = ResolveMap(),
Pk3File = ResolvePk3(),
Overwrite = Force,
ExcludeSources = Exclude,
IgnoreSources = Ignore,
UnpackedSources = NoPack,
UnscannedSources = NoScan,
ModFolders = Mods,
DryRun = DryRun,
IncludeSource = Source,
OnlySource = Source,
LoadPk3s = IncludePk3,
LogLevel = Verbosity,
Rename = Rename,
RequireAllAssets = !Loose,
UseShaderlist = Shaderlist,
ShaderDebug = ShaderDebug,
ReferenceDebug = ReferenceDebug,
});
Expand Down Expand Up @@ -150,7 +165,8 @@ private FileInfo ResolveMap()
pk3Location = etmain;
}

pk3 = new FileInfo(Path.Combine(pk3Location.FullName, Path.ChangeExtension(pk3Name, ".pk3")));
string outName = Path.ChangeExtension(pk3Name, Source ? ".zip" : ".pk3");
pk3 = new FileInfo(Path.Combine(pk3Location.FullName, outName));
}
else
{
Expand Down
27 changes: 0 additions & 27 deletions Pack3r.Core/Extensions/ROMCharComparer.cs

This file was deleted.

71 changes: 24 additions & 47 deletions Pack3r.Core/Extensions/StringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,23 @@ public static class StringExtensions
{
public static string NormalizePath(this string path) => path.Replace(Path.DirectorySeparatorChar, '/');

public static ReadOnlyMemory<char> ChangeExtension(this ReadOnlyMemory<char> file, ReadOnlySpan<char> extension)
public static QString ChangeExtension(this ReadOnlyMemory<char> file, ReadOnlySpan<char> extension)
{
int extensionLength = file.GetExtension().Length;

var withoutExtension = file[..^extensionLength];
ReadOnlySpan<char> current = file.GetExtension();

if (extension.IsEmpty)
return withoutExtension;
{
return file[..^current.Length];
}

return $"{withoutExtension.Span}{extension}".AsMemory();
if (current.SequenceEqual(extension))
{
return file;
}

return $"{file[..^current.Length]}{extension}".AsMemory();
}

public static TextureExtension GetTextureExtension(this ReadOnlyMemory<char> path) => GetTextureExtension(path.Span);
public static TextureExtension GetTextureExtension(this string path) => GetTextureExtension(path.AsSpan());
public static TextureExtension GetTextureExtension(this ReadOnlySpan<char> path)
{
Expand All @@ -41,29 +45,9 @@ public static TextureExtension GetTextureExtension(this ReadOnlySpan<char> path)
return TextureExtension.Other;
}

public static ArraySegment<Range> Split(
this ReadOnlyMemory<char> value,
char separator,
StringSplitOptions options = StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
{
var ranges = new Range[32];

int count = value.Span.Split(ranges.AsSpan(), separator, options);

if (count == 0)
{
ranges[0] = Range.All;
count = 1;
}

return new ArraySegment<Range>(ranges, 0, count);
}

public static bool TryReadUpToWhitespace(in this ReadOnlyMemory<char> value, out ReadOnlyMemory<char> token)
{
var span = value.Span;

int space = span.IndexOfAny(Tokens.SpaceOrTab);
int space = value.Span.IndexOfAny(Tokens.SpaceOrTab);

if (space == -1)
{
Expand All @@ -77,9 +61,7 @@ public static bool TryReadUpToWhitespace(in this ReadOnlyMemory<char> value, out

public static bool TryReadPastWhitespace(in this ReadOnlyMemory<char> value, out ReadOnlyMemory<char> token)
{
var span = value.Span;

int space = span.IndexOfAny(Tokens.SpaceOrTab);
int space = value.Span.IndexOfAny(Tokens.SpaceOrTab);

if (space == -1)
{
Expand Down Expand Up @@ -111,30 +93,25 @@ public static bool MatchKeyword(in this Line line, string prefix, out ReadOnlyMe

public static ReadOnlyMemory<char> TrimQuotes(this ReadOnlyMemory<char> token)
{
var keySpan = token.Span;

if (keySpan.Length >= 2 &&
keySpan[0] == '"' &&
keySpan[^1] == '"')
{
return token[1..^1];
}

_ = TryTrimQuotes(token, out token);
return token;
}

public static bool TryTrimQuotes(this ReadOnlyMemory<char> token, out ReadOnlyMemory<char> trimmed)
{
var keySpan = token.Span;

if (keySpan.Length >= 2 &&
keySpan[0] == '"' &&
keySpan[^1] == '"')
if (token.Length >= 2)
{
trimmed = token[1..^1];
return true;
var keySpan = token.Span;

if (keySpan[0] == '"' &&
keySpan[^1] == '"')
{
trimmed = token[1..^1];
return true;
}
}


trimmed = token;
return false;
}
Expand Down
7 changes: 3 additions & 4 deletions Pack3r.Core/IO/AssetSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ namespace Pack3r.IO;
public abstract class AssetSource : IDisposable
{
public abstract string RootPath { get; }
public abstract IAsset? GetShaderlist();
public abstract IAsyncEnumerable<Shader> EnumerateShaders(
IShaderParser parser,
Func<string, bool> skipPredicate,
Expand All @@ -18,7 +17,7 @@ public abstract IAsyncEnumerable<Shader> EnumerateShaders(
/// <summary>
/// Whether this source is used to discover files, but never pack them (pak0, mod files etc).
/// </summary>
public bool IsExcluded { get; }
public bool NotPacked { get; }

/// <summary>
/// Display name (folder/pk3 name).
Expand All @@ -31,9 +30,9 @@ public abstract IAsyncEnumerable<Shader> EnumerateShaders(

protected bool _disposed;

protected AssetSource(bool isExcluded)
protected AssetSource(bool notPacked)
{
IsExcluded = isExcluded;
NotPacked = notPacked;
_assetsLazy = new(InitializeAssets, LazyThreadSafetyMode.ExecutionAndPublication);
}

Expand Down
11 changes: 2 additions & 9 deletions Pack3r.Core/IO/DirectoryAssetSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
namespace Pack3r.IO;

[DebuggerDisplay("{DebuggerDisplay,nq}")]
public sealed class DirectoryAssetSource(DirectoryInfo directory, bool isExcluded) : AssetSource(isExcluded)
public sealed class DirectoryAssetSource(DirectoryInfo directory, bool notPacked) : AssetSource(notPacked)
{
public DirectoryInfo Directory => directory;
public override string RootPath => directory.FullName;

public override string ToString() => $"{{ Dir: {Directory.FullName} }}";
internal string DebuggerDisplay => $"{{ Dir src: '{Directory.Name}' (Excluded: {IsExcluded}) }}";
internal string DebuggerDisplay => $"{{ Dir src: '{Directory.Name}' (Excluded: {NotPacked}) }}";

public override async IAsyncEnumerable<Shader> EnumerateShaders(
IShaderParser parser,
Expand Down Expand Up @@ -41,11 +41,4 @@ protected override IEnumerable<IAsset> EnumerateAssets()
.Where(f => Tokens.PackableFile().IsMatch(f.FullName))
.Select(f => new FileAsset(this, f));
}

public override IAsset? GetShaderlist()
{
return new FileAsset(
this,
new FileInfo(Path.Combine(Directory.FullName, "scripts", "shaderlist.txt")));
}
}
20 changes: 2 additions & 18 deletions Pack3r.Core/IO/Pk3AssetSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@
namespace Pack3r.IO;

[DebuggerDisplay("{DebuggerDisplay,nq}")]
public sealed class Pk3AssetSource(string path, bool isExcluded) : AssetSource(isExcluded)
public sealed class Pk3AssetSource(string path, bool notPacked) : AssetSource(notPacked)
{
public string ArchivePath => path;
public override string RootPath => ArchivePath;

private readonly ZipArchive _archive = ZipFile.OpenRead(path);

public override string ToString() => $"{{ Pk3: {ArchivePath} }}";
internal string DebuggerDisplay => $"{{ Pk3 src: '{Path.GetFileName(ArchivePath)}' (Excluded: {IsExcluded}) }}";
internal string DebuggerDisplay => $"{{ Pk3 src: '{Path.GetFileName(ArchivePath)}' (Excluded: {NotPacked}) }}";

public override async IAsyncEnumerable<Shader> EnumerateShaders(
IShaderParser parser,
Expand Down Expand Up @@ -56,20 +56,4 @@ protected override IEnumerable<IAsset> EnumerateAssets()
.Where(entry => entry.FullName.Length < Global.MAX_QPATH && Tokens.PackableFile().IsMatch(entry.FullName.GetExtension()))
.Select(entry => new Pk3Asset(this, entry));
}

public override IAsset? GetShaderlist()
{
ObjectDisposedException.ThrowIf(_disposed, this);

ZipArchiveEntry? entry =
_archive.GetEntry("scripts/shaderlist.txt") ??
_archive.GetEntry("scripts\\shaderlist.txt");

if (entry is not null)
{
return new Pk3Asset(this, entry);
}

return null;
}
}
Loading