Skip to content

Commit

Permalink
Merge pull request #28 from BigBang1112/dev
Browse files Browse the repository at this point in the history
Alpha.3
  • Loading branch information
BigBang1112 authored Jan 8, 2025
2 parents cee2f06 + 385a43e commit ef26fae
Show file tree
Hide file tree
Showing 155 changed files with 4,242 additions and 343 deletions.
14 changes: 14 additions & 0 deletions NationsConverter.sln
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FixStadiumGrass", "Tools\Fi
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UpdateCampaign", "Tools\UpdateCampaign\UpdateCampaign.csproj", "{E8DF5D06-99FE-4433-BB54-EE2CDA8E92DD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChangeDefaultCar", "Tools\ChangeDefaultCar\ChangeDefaultCar.csproj", "{74BE0A09-FA0D-401E-9CE3-2FCEFB6C8471}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LoadMacroblockInfo", "Tools\LoadMacroblockInfo\LoadMacroblockInfo.csproj", "{DB39D314-FEC4-4A90-92AC-3964B444CD23}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -67,6 +71,14 @@ Global
{E8DF5D06-99FE-4433-BB54-EE2CDA8E92DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E8DF5D06-99FE-4433-BB54-EE2CDA8E92DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E8DF5D06-99FE-4433-BB54-EE2CDA8E92DD}.Release|Any CPU.Build.0 = Release|Any CPU
{74BE0A09-FA0D-401E-9CE3-2FCEFB6C8471}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{74BE0A09-FA0D-401E-9CE3-2FCEFB6C8471}.Debug|Any CPU.Build.0 = Debug|Any CPU
{74BE0A09-FA0D-401E-9CE3-2FCEFB6C8471}.Release|Any CPU.ActiveCfg = Release|Any CPU
{74BE0A09-FA0D-401E-9CE3-2FCEFB6C8471}.Release|Any CPU.Build.0 = Release|Any CPU
{DB39D314-FEC4-4A90-92AC-3964B444CD23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DB39D314-FEC4-4A90-92AC-3964B444CD23}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DB39D314-FEC4-4A90-92AC-3964B444CD23}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DB39D314-FEC4-4A90-92AC-3964B444CD23}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -81,6 +93,8 @@ Global
{0A67AEBB-3ACE-456B-8D58-2899F7BF4E52} = {C4686498-B539-4420-BCB7-A5AEB884506B}
{18967A84-E3C3-4A10-9B59-B5DA6A6D7C6E} = {00F42213-4CBA-4120-8C67-EC7470AEEE1A}
{E8DF5D06-99FE-4433-BB54-EE2CDA8E92DD} = {00F42213-4CBA-4120-8C67-EC7470AEEE1A}
{74BE0A09-FA0D-401E-9CE3-2FCEFB6C8471} = {00F42213-4CBA-4120-8C67-EC7470AEEE1A}
{DB39D314-FEC4-4A90-92AC-3964B444CD23} = {00F42213-4CBA-4120-8C67-EC7470AEEE1A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5F80CCCE-40A6-4BE9-8853-5A8E3D4C276A}
Expand Down
62 changes: 59 additions & 3 deletions Src/NationsConverter/CustomContentManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using GBX.NET;
using GBX.NET.Engines.Game;
using GBX.NET.Engines.GameData;
using GBX.NET.Engines.Plug;
using Microsoft.Extensions.Logging;
using NationsConverter.Models;
using NationsConverter.Stages;
Expand Down Expand Up @@ -84,7 +85,7 @@ public CGameCtnAnchoredObject PlaceItemRaw(string itemPath, Vec3 pos, Vec3 rot,
if (lightProperties?.Length > 0)
{
// so that you can match it in CreateEntryFromLocalGbxFile/CreateEntryFromZippedGbxFile
itemLights.Add(Path.Combine("Items", rootFolderName, itemPath), lightProperties);
itemLights.TryAdd(Path.Combine("Items", rootFolderName, itemPath), lightProperties);
}

var item = mapOut.PlaceAnchoredObject(new(Path.Combine(rootFolderName, itemPath.Replace("�", "")).Replace('/', '\\'), ItemCollection, itemModelAuthor), pos, rot, pivot);
Expand All @@ -94,7 +95,7 @@ public CGameCtnAnchoredObject PlaceItemRaw(string itemPath, Vec3 pos, Vec3 rot,

public CGameCtnBlock PlaceBlock(string blockModel, Int3 coord, Direction dir, bool isGround = false, byte variant = 0, byte subVariant = 0)
{
var blockPath = $"{blockModel.Replace('/', '\\')}.Block.Gbx";
var blockPath = $"{blockModel}.Block.Gbx";

var block = mapOut.PlaceBlock($"{Path.Combine(rootFolderName, blockPath).Replace('/', '\\')}_CustomBlock", coord, dir, isGround, variant, subVariant);

Expand Down Expand Up @@ -215,9 +216,64 @@ private bool TryInjectLights(Stream sourceItemGbxStream, Stream outputItemGbxStr
return false;
}

// 1. open item gbx fully
// 1. open item gbx fully (issue with "Failed to read compressed data" if not using MemoryStream)
using var ms = new MemoryStream();
sourceItemGbxStream.CopyTo(ms);
ms.Position = 0;
var itemGbx = Gbx.Parse<CGameItemModel>(ms);

// 2. add light layer according to lightProperties
if (itemGbx.Node.EntityModelEdition is not CGameCommonItemEntityModelEdition { MeshCrystal: not null } entityEdition)
{
return false;
}

var lightLayer = entityEdition.MeshCrystal
.Layers
.OfType<CPlugCrystal.LightLayer>()
.FirstOrDefault();

if (lightLayer is null)
{
lightLayer = new CPlugCrystal.LightLayer
{
Ver = 2,
LayerName = "Light",
LayerId = "Layer4",
IsEnabled = true
};
entityEdition.MeshCrystal.Layers.Add(lightLayer);
}

var lights = lightProperties.Select(props =>
{
var userLight = new CPlugLightUserModel
{
Color = props.Color,
Distance = props.Distance,
Intensity = props.Intensity,
NightOnly = props.NightOnly,
SpotInnerAngle = props.SpotInnerAngle,
SpotOuterAngle = props.SpotOuterAngle,
};
userLight.CreateChunk<CPlugLightUserModel.Chunk090F9000>().Version = 1;
return userLight;
});

var prevLightCount = lightLayer.Lights?.Length ?? 0;

var lightPositions = lightProperties.Select((x, i) => new CPlugCrystal.LightPos
{
U01 = i + prevLightCount, // index of the light
U02 = new(0, 0, 0, 0, 0, 0, 0, 0, 0, x.Position.X, x.Position.Y, x.Position.Z)
});

lightLayer.Lights = (lightLayer.Lights ?? []).Concat(lights).ToArray();
lightLayer.LightPositions = (lightLayer.LightPositions ?? []).Concat(lightPositions).ToArray();

// 3. write uncompressed to outputItemGbxStream
itemGbx.BodyCompression = GbxCompression.Uncompressed;
itemGbx.Save(outputItemGbxStream);

return true;
}
Expand Down
4 changes: 2 additions & 2 deletions Src/NationsConverter/Extracts/CoveredZoneBlockInfoExtract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public ImmutableHashSet<CGameCtnBlock> Extract()

var groundPositions = new HashSet<Int3>();

foreach (var (block, conversion) in conversionSet.GetBlockConversionPairs(mapIn))
foreach (var (block, conversion) in conversionSet.GetBlockConversionPairs(mapIn, logger))
{
if (conversion.ZoneHeight is not null)
{
Expand All @@ -41,7 +41,7 @@ public ImmutableHashSet<CGameCtnBlock> Extract()

var coveredZoneBlocks = ImmutableHashSet.CreateBuilder<CGameCtnBlock>();

foreach (var (block, conversion) in conversionSet.GetBlockConversionPairs(mapIn))
foreach (var (block, conversion) in conversionSet.GetBlockConversionPairs(mapIn, logger))
{
if (!block.IsGround || conversion.ZoneHeight is null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public ImmutableDictionary<Int3, string> Extract()
{
if (conversionSet.BlockTerrainModifiers.TryGetValue(block.Name, out var terrainModifier))
{
terrainModifierZones[block.Coord] = terrainModifier;
terrainModifierZones[block.Coord with { Y = 0 }] = terrainModifier;
continue;
}

Expand Down
1 change: 1 addition & 0 deletions Src/NationsConverter/Models/ManualConversionBlockModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public sealed class ManualConversionBlockModel
public int Offset1Y { get; set; }
public int Offset2Y { get; set; }
public bool NoItem { get; set; }
public bool NoItems { get; set; }
public bool Bit21 { get; set; }
public int Dir { get; set; }
public bool IsRelativeOffset { get; set; }
Expand Down
2 changes: 2 additions & 0 deletions Src/NationsConverter/Models/ManualConversionItemModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public sealed class ManualConversionItemModel
public float RotY { get; set; }
public float RotZ { get; set; }
public bool AlwaysStaticObject { get; set; }
public bool OnlyAir { get; set; }
public bool OnlyGround { get; set; }

/// <summary>
/// If item from the Modernized sub-category should be used when Modernized is applied. False will always pick Classic. Only has effect in the Crystal category.
Expand Down
1 change: 1 addition & 0 deletions Src/NationsConverter/Models/ManualConversionModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public sealed class ManualConversionModel : ManualConversionModifierModel
public bool ForceGroundItem { get; set; }
public ManualConversionSkinModel? Skin { get; set; }
public DifficultyColor? Color { get; set; }
public bool AirModifiable { get; set; }

/// <summary>
/// If items from the Modernized sub-category should be used when Modernized is applied. False will always pick Classic. Only has effect in the Crystal category.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ public class ManualConversionModifierModel : ConversionModifierModel
public ManualConversionBlockModel? Conversion { get; set; }
public ManualConversionBlockModel[]? Conversions { get; set; }
public Dictionary<int, ManualConversionVariantModel>? ConversionVariants { get; set; }
public Dictionary<string, Dictionary<int, ManualConversionVariantModel>>? ConversionVariantsByBlock { get; set; }
public LightPropertiesModel[]? Lights { get; set; }
}
13 changes: 9 additions & 4 deletions Src/NationsConverter/Models/ManualConversionSetModel.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using GBX.NET.Engines.Game;
using Microsoft.Extensions.Logging;
using NationsConverterShared.Models;
using YamlDotNet.Serialization;

Expand All @@ -16,14 +17,14 @@ public string Environment
set => environment = value;
}

private readonly HashSet<string> blockNamesNotFound = [];

public string? DefaultZoneBlock { get; set; }
public Dictionary<string, string> BlockTerrainModifiers { get; set; } = [];
public float DecorationYOffset { get; set; }
public Dictionary<string, ManualConversionDecorationModel> Decorations { get; set; } = [];
public HashSet<string>? TerrainModifiers { get; set; }
public float WaterHeight { get; set; }
[Obsolete("Pylon is now taken from zone blocks")]
public string? Pylon { get; set; }
public Dictionary<string, ManualConversionModel> Blocks { get; set; } = [];
public int PillarOffset { get; set; }

Expand All @@ -50,7 +51,7 @@ public ManualConversionSetModel Fill(ConversionSetModel conversionSet)
if (!Blocks.TryGetValue(block, out var manualConversion) || manualConversion is null)
{
manualConversion = new ManualConversionModel();
Blocks.Add(block, manualConversion);
Blocks[block] = manualConversion;
}

manualConversion ??= new ManualConversionModel();
Expand Down Expand Up @@ -112,14 +113,18 @@ public ManualConversionSetModel Fill(ConversionSetModel conversionSet)
return this;
}

public IEnumerable<KeyValuePair<CGameCtnBlock, ManualConversionModel>> GetBlockConversionPairs(CGameCtnChallenge map)
public IEnumerable<KeyValuePair<CGameCtnBlock, ManualConversionModel>> GetBlockConversionPairs(CGameCtnChallenge map, ILogger logger)
{
foreach (var block in map.GetBlocks())
{
if (Blocks.TryGetValue(block.Name, out var conversion) && conversion is not null)
{
yield return KeyValuePair.Create(block, conversion);
}
else if (blockNamesNotFound.Add(block.Name))
{
logger.LogWarning("Block {BlockName} not found in conversion set!", block.Name);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace NationsConverter.Stages;
namespace NationsConverter.Models;

public sealed class SkinInfoModel
{
Expand Down
6 changes: 3 additions & 3 deletions Src/NationsConverter/NationsConverter.csproj
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<Version>2.0.0-alpha.2</Version>
<Version>2.0.0-alpha.3</Version>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="ByteSize" Version="2.1.2" />
<PackageReference Include="GBX.NET" Version="2.1.0-nightly.20241219.e0c54b9" />
<PackageReference Include="GBX.NET.Tool" Version="0.3.0" />
<PackageReference Include="GBX.NET" Version="2.1.0" />
<PackageReference Include="GBX.NET.Tool" Version="0.3.1" />
<PackageReference Include="YamlDotNet" Version="16.2.1" />
<PackageReference Include="Vecc.YamlDotNet.Analyzers.StaticGenerator" Version="16.2.1">
<PrivateAssets>all</PrivateAssets>
Expand Down
6 changes: 6 additions & 0 deletions Src/NationsConverter/NationsConverterConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ public class NationsConverterConfig : Config
[YamlMember(Description = "Places invisible transformation gate on the start block.")]
public bool PlaceTransformationGate { get; set; } = true;

[YamlMember(Description = "Place a visible transformation gate instead of the invisible one.")]
public bool UseVisibleTransformationGate { get; set; }

[YamlMember(Description = "Applies the default car from the map to the converted map. This won't make a difference without Editor++ installed.")]
public bool ApplyDefaultCar { get; set; }

[YamlMember(Description = "Keeps the map validated with its medal times. PLEASE use only if you're certain the map is gonna be possible to finish.")]
public bool KeepMedalTimes { get; set; }

Expand Down
19 changes: 13 additions & 6 deletions Src/NationsConverter/NationsConverterTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public Gbx<CGameCtnChallenge> Produce()
var waterStage = new WaterStage(mapIn, mapOut, conversionSet, coveredZoneBlocks, isManiaPlanet, logger);
waterStage.Convert();

var pylonStage = new PylonStage(mapIn, mapOut, conversionSet, customContentManager);
var pylonStage = new PylonStage(mapIn, mapOut, conversionSet, customContentManager, logger);
pylonStage.Convert();

var decorationStage = new DecorationStage(mapIn, mapOut, conversionSet, Config, customContentManager, logger);
Expand Down Expand Up @@ -103,6 +103,9 @@ public Gbx<CGameCtnChallenge> Produce()
? TextFormatter.Deformat(mapIn.MapName)
: GbxPath.GetFileNameWithoutExtension(gbxMapIn.FilePath);

fileNameWithoutExtension = Path.GetInvalidFileNameChars()
.Aggregate(fileNameWithoutExtension, (current, c) => current.Replace(c, '_'));

return new Gbx<CGameCtnChallenge>(mapOut)
{
FilePath = Path.Combine("Maps", "GbxTools", "NationsConverter", $"{fileNameWithoutExtension}.Map.Gbx")
Expand Down Expand Up @@ -196,15 +199,19 @@ private CGameCtnChallenge CreateBaseMap()
mapOut.CreateChunk<CGameCtnChallenge.Chunk0304302A>();
mapOut.CreateChunk<CGameCtnChallenge.Chunk03043034>();

var oldThumbnailChunk = mapIn.Chunks.Get<CGameCtnChallenge.Chunk03043028>();
if (oldThumbnailChunk is null)
var newThumbnailChunk = mapIn.Chunks.Get<CGameCtnChallenge.Chunk03043036>();
if (newThumbnailChunk is null)
{
mapOut.CreateChunk<CGameCtnChallenge.Chunk03043036>().U01 = 10;
var oldThumbnailChunk = mapIn.Chunks.Get<CGameCtnChallenge.Chunk03043028>();
if (oldThumbnailChunk is not null)
{
mapOut.Chunks.Add(oldThumbnailChunk);
mapOut.HasCustomCamThumbnail = mapIn.HasCustomCamThumbnail;
}
}
else
{
mapOut.Chunks.Add(oldThumbnailChunk);
mapOut.HasCustomCamThumbnail = mapIn.HasCustomCamThumbnail;
mapOut.Chunks.Add(newThumbnailChunk);
}

mapOut.CreateChunk<CGameCtnChallenge.Chunk0304303E>();
Expand Down
8 changes: 6 additions & 2 deletions Src/NationsConverter/Stages/BlockStageBase.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
using GBX.NET;
using GBX.NET.Engines.Game;
using Microsoft.Extensions.Logging;
using NationsConverter.Models;

namespace NationsConverter.Stages;

internal abstract class BlockStageBase : EnvironmentStageBase
{
private readonly CGameCtnChallenge mapIn;
private readonly ILogger logger;

/// <summary>
/// Block size in small units.
Expand All @@ -16,7 +18,7 @@ internal abstract class BlockStageBase : EnvironmentStageBase
protected Int3 TotalOffset { get; }
protected ManualConversionSetModel ConversionSet { get; }

public BlockStageBase(CGameCtnChallenge mapIn, CGameCtnChallenge mapOut, ManualConversionSetModel conversionSet)
public BlockStageBase(CGameCtnChallenge mapIn, CGameCtnChallenge mapOut, ManualConversionSetModel conversionSet, ILogger logger)
: base(mapIn)
{
this.mapIn = mapIn;
Expand All @@ -28,13 +30,15 @@ public BlockStageBase(CGameCtnChallenge mapIn, CGameCtnChallenge mapOut, ManualC
}
TotalOffset = CenterOffset + (0, -mapIn.DecoBaseHeightOffset, 0);
ConversionSet = conversionSet;

this.logger = logger;
}

protected abstract void ConvertBlock(CGameCtnBlock block, ManualConversionModel conversion);

public virtual void Convert()
{
foreach (var (block, conversion) in ConversionSet.GetBlockConversionPairs(mapIn))
foreach (var (block, conversion) in ConversionSet.GetBlockConversionPairs(mapIn, logger))
{
ConvertBlock(block, conversion);
}
Expand Down
2 changes: 1 addition & 1 deletion Src/NationsConverter/Stages/MediaTrackerStage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public MediaTrackerStage(
CGameCtnChallenge mapOut,
NationsConverterConfig config,
ManualConversionSetModel conversionSet,
ILogger logger) : base(mapIn, mapOut, conversionSet)
ILogger logger) : base(mapIn, mapOut, conversionSet, logger)
{
this.mapIn = mapIn;
this.mapOut = mapOut;
Expand Down
7 changes: 6 additions & 1 deletion Src/NationsConverter/Stages/PlaceBaseZoneStage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public PlaceBaseZoneStage(
ManualConversionSetModel conversionSet,
CustomContentManager customContentManager,
ImmutableDictionary<Int3, string> terrainModifierZones,
ILogger logger) : base(mapIn, mapOut, conversionSet)
ILogger logger) : base(mapIn, mapOut, conversionSet, logger)
{
this.mapIn = mapIn;
this.mapOut = mapOut;
Expand Down Expand Up @@ -84,6 +84,11 @@ protected override void ConvertBlock(CGameCtnBlock block, ManualConversionModel
{
var pos = block.Coord + unit - min;

if (occupiedZone.GetLength(0) <= pos.X || occupiedZone.GetLength(1) <= pos.Z)
{
continue;
}

if (!occupiedZone[pos.X, pos.Z])
{
occupiedZone[pos.X, pos.Z] = pos.Y == baseHeight + 1 + mapIn.DecoBaseHeightOffset;
Expand Down
Loading

0 comments on commit ef26fae

Please sign in to comment.