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

Jass decompiler improvements #62

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions src/War3Net.Build/Extensions/SoundExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// ------------------------------------------------------------------------------
// <copyright file="RegionExtensions.cs" company="Drake53">
// Licensed under the MIT license.
// See the LICENSE file in the project root for more information.
// </copyright>
// ------------------------------------------------------------------------------

using War3Net.Build.Audio;
using War3Net.Build.Environment;

namespace War3Net.Build.Extensions
{

public static class SoundExtensions
{
public static string GetVariableName(this Sound sound)
{
return $"gg_snd_{sound.Name.Replace(' ', '_')}";
}
}
}
2 changes: 1 addition & 1 deletion src/War3Net.Build/Extensions/UnitDataExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public static class UnitDataExtensions

public static string GetVariableName(this UnitData unitData)
{
return $"gg_unit_{unitData.TypeId.ToRawcode()}_{unitData.CreationNumber:D4}";
return $"{(unitData.IsItem() ? "gg_item_" : "gg_unit_")}{unitData.TypeId.ToRawcode()}_{unitData.CreationNumber:D4}";
}

public static string GetDropItemsFunctionName(this UnitData unitData, int id)
Expand Down
4 changes: 4 additions & 0 deletions src/War3Net.Build/War3Net.Build.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,8 @@
<PackageReference Include="War3Net.CodeAnalysis.Transpilers" Version="$(War3NetCodeAnalysisTranspilersVersion)" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\War3Net.CodeAnalysis.Decompilers\War3Net.CodeAnalysis.Decompilers.csproj" />
</ItemGroup>

</Project>
661 changes: 326 additions & 335 deletions src/War3Net.CodeAnalysis.Decompilers/Audio/MapSoundsDecompiler.cs

Large diffs are not rendered by default.

121 changes: 85 additions & 36 deletions src/War3Net.CodeAnalysis.Decompilers/DecompilationContext.cs
Original file line number Diff line number Diff line change
@@ -1,56 +1,35 @@
// ------------------------------------------------------------------------------
// <copyright file="DecompilationContext.cs" company="Drake53">
//
// Licensed under the MIT license.
// See the LICENSE file in the project root for more information.
// </copyright>
// ------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;

using War3Net.Build;
using War3Net.Build.Info;
using War3Net.Build.Script;
using War3Net.CodeAnalysis.Jass;
using War3Net.CodeAnalysis.Jass.Syntax;

namespace War3Net.CodeAnalysis.Decompilers
{
internal sealed class DecompilationContext
public class DecompilationContext
{
public DecompilationContext(Map map, Campaign? campaign, TriggerData? triggerData)
public DecompilationContext(JassCompilationUnitSyntax compilationUnit, DecompileOptions options = null, MapInfo mapInfo = null, TriggerData triggerData = null)
{
if (map is null)
{
throw new ArgumentNullException(nameof(map));
}

if (map.Info is null)
{
throw new Exception();
}

if (map.Info.ScriptLanguage != ScriptLanguage.Jass)
{
throw new Exception();
}
CompilationUnit = compilationUnit;
Options = options ?? new DecompileOptions();
MapInfo = mapInfo;

if (string.IsNullOrEmpty(map.Script))
{
throw new Exception();
}

ObjectData = new ObjectDataContext(map, campaign);
TriggerData = new TriggerDataContext(triggerData);

var compilationUnit = JassSyntaxFactory.ParseCompilationUnit(map.Script);

var comments = new List<JassCommentSyntax>();
var functionDeclarationsBuilder = ImmutableDictionary.CreateBuilder<string, FunctionDeclarationContext>(StringComparer.Ordinal);
var variableDeclarationsBuilder = ImmutableDictionary.CreateBuilder<string, VariableDeclarationContext>(StringComparer.Ordinal);

foreach (var declaration in compilationUnit.Declarations)
foreach (var declaration in CompilationUnit.Declarations)
{
if (declaration is JassCommentSyntax comment)
{
Expand Down Expand Up @@ -80,21 +59,91 @@ public DecompilationContext(Map map, Campaign? campaign, TriggerData? triggerDat
FunctionDeclarations = functionDeclarationsBuilder.ToImmutable();
VariableDeclarations = variableDeclarationsBuilder.ToImmutable();


ImportedFileNames = new(StringComparer.OrdinalIgnoreCase);
MaxPlayerSlots = mapInfo != null && mapInfo.EditorVersion >= EditorVersion.v6060 ? 24 : 12;
}

public TriggerDataContext TriggerData { get; }
public ImmutableDictionary<string, FunctionDeclarationContext> FunctionDeclarations { get; }
public ImmutableDictionary<string, VariableDeclarationContext> VariableDeclarations { get; }
public HashSet<string> ImportedFileNames { get; }
public int MaxPlayerSlots { get; }

public HashSet<IStatementLineSyntax> HandledStatements = new HashSet<IStatementLineSyntax>();
public JassCompilationUnitSyntax CompilationUnit { get; }
public MapInfo MapInfo { get; }
public DecompileOptions Options { get; }

MaxPlayerSlots = map.Info.EditorVersion >= EditorVersion.v6060 ? 24 : 12;
private readonly Dictionary<string, object> _variableNameToValueMapping = new();
private readonly List<object> _values = new();
private int _lastCreationNumber;

public int GetNextCreationNumber()
{
return _lastCreationNumber++;
}

public ObjectDataContext ObjectData { get; }
public string GetVariableName(object value)
{
return _variableNameToValueMapping.FirstOrDefault(x => x.Value == value).Key;
}

public TriggerDataContext TriggerData { get; }
public void Add<T>(T value, string variableName = null) where T : class
{
if (variableName != null)
{
_variableNameToValueMapping[variableName] = value;
}

public ImmutableDictionary<string, FunctionDeclarationContext> FunctionDeclarations { get; }
_values.Add(value);
}

public ImmutableDictionary<string, VariableDeclarationContext> VariableDeclarations { get; }
public void Add_Struct<T>(T value, string variableName = null) where T : struct
{
Add(new Nullable_Class<T>(value), variableName);
}

public HashSet<string> ImportedFileNames { get; }
public T Get<T>(string variableName) where T : class
{
if (variableName == null)
{
return default;
}

return _variableNameToValueMapping.GetValueOrDefault(variableName) as T;
}

public Nullable_Class<T> Get_Struct<T>(string variableName = null) where T : struct
{
return Get<Nullable_Class<T>>(variableName);
}

public T GetLastCreated<T>() where T : class
{
return _values.OfType<T>().LastOrDefault();
}

public Nullable_Class<T> GetLastCreated_Struct<T>() where T : struct
{
return GetLastCreated<Nullable_Class<T>>();
}

public IEnumerable<T> GetAll<T>() where T : class
{
return _values.OfType<T>();
}

public IEnumerable<Nullable_Class<T>> GetAll_Struct<T>() where T : struct
{
return GetAll<Nullable_Class<T>>();
}

private const string PSEUDO_VARIABLE_PREFIX = "##PSEUDO_VARIABLE_PREFIX##";
internal string CreatePseudoVariableName(string type, string name = "")
{
return PSEUDO_VARIABLE_PREFIX + "_" + type.ToString() + "_" + name;
}

public int MaxPlayerSlots { get; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// ------------------------------------------------------------------------------
//
// Licensed under the MIT license.
// See the LICENSE file in the project root for more information.
//
// ------------------------------------------------------------------------------

using War3Net.Build.Audio;
using War3Net.Build.Environment;
using War3Net.Build.Widget;

namespace War3Net.CodeAnalysis.Decompilers
{
public class DecompileOptions
{
public MapCamerasFormatVersion mapCamerasFormatVersion;
public bool mapCamerasUseNewFormat;
public MapRegionsFormatVersion mapRegionsFormatVersion;
public MapSoundsFormatVersion mapSoundsFormatVersion;
public MapWidgetsFormatVersion mapWidgetsFormatVersion;
public MapWidgetsSubVersion mapWidgetsSubVersion;
public bool mapWidgetsUseNewFormat = default;
public SpecialDoodadVersion specialDoodadVersion;
}
}
Loading