Files
sbox-public/engine/Sandbox.Tools/MapEditor/Hammer.SaveLoad.cs
s&box team 71f266059a Open source release
This commit imports the C# engine code and game files, excluding C++ source code.

[Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
2025-11-24 09:05:18 +00:00

99 lines
3.7 KiB
C#

using Editor.MapDoc;
namespace Editor.MapEditor;
public static partial class Hammer
{
/// <summary>
/// Called just before anything is saved to a map file.
/// This is the ideal place to manipulate the map document just before save.
/// </summary>
internal static void PreSaveMap( MapDocument mapDoc )
{
}
/// <summary>
/// Called after the map has been successfully written to disk.
/// </summary>
internal static void MapAssetSaved( int assetIndex, MapDocument map )
{
var mapAsset = AssetSystem.Get( (uint)assetIndex );
Assert.NotNull( mapAsset );
var usedPackages = GetUsedPackages( map );
//
// References that we need to download to edit this map
// These will be re-downloaded when opening the editor
// if it doesn't already have them downloaded.
//
{
mapAsset.Publishing.ProjectConfig.EditorReferences = new();
//
// Collect all packages our assets use and save them as metadata, so we can make sure we have them downloaded before opening
//
var packages = mapAsset.GetReferences( false ).Where( a => a.Package != null ).Select( a => $"{a.Package.FullIdent}#{a.Package.Revision.VersionId}" ).Distinct();
mapAsset.Publishing.ProjectConfig.EditorReferences.AddRange( packages.ToList() );
//
// Add any games we're referencing. We'll want to re-reference them when opening the map
//
mapAsset.Publishing.ProjectConfig.EditorReferences.AddRange( usedPackages.Where( x => x.TypeName == "game" ).Select( x => x.FullIdent ) );
//
// Lowercase and remove duplicates
//
mapAsset.Publishing.ProjectConfig.EditorReferences = mapAsset.Publishing.ProjectConfig.EditorReferences.Select( x => x.ToLowerInvariant() ).Distinct().OrderBy( x => x ).ToList();
}
//
// References to addons that this map needs to run. We try to work this out by looking at the entities
// used and then looking at the package they're from, and if the package is an addon we use it. We assume
// that if they're referencing a specific game then the map will always be run with that game.
//
{
mapAsset.Publishing.ProjectConfig.PackageReferences = new(); // maybe we shouldn't clear this? No reason why not right now.
mapAsset.Publishing.ProjectConfig.PackageReferences.AddRange( usedPackages.Where( x => x.TypeName == "addon" ).Select( x => x.FullIdent ) );
//
// Lowercase and remove duplicates
//
mapAsset.Publishing.ProjectConfig.PackageReferences = mapAsset.Publishing.ProjectConfig.PackageReferences.Select( x => x.ToLowerInvariant() ).Distinct().OrderBy( x => x ).ToList();
}
// Save the updated publish config
mapAsset.MetaData.Set( "publish", mapAsset.Publishing );
}
/// <summary>
/// Get a list of packages used in this map, based primarily on the entities used.
/// </summary>
static Package[] GetUsedPackages( MapDocument map )
{
var usedEntityClasses = map.World.Children.OfType<MapEntity>().Select( e => e.ClassName ).Distinct();
List<Package> usedPackges = new();
foreach ( var className in usedEntityClasses )
{
var managedClass = GameData.EntityClasses.Where( c => c.Name == className ).FirstOrDefault();
if ( managedClass == null || managedClass.Package == null ) continue;
usedPackges.Add( managedClass.Package );
}
return usedPackges.Distinct().ToArray();
}
/// <summary>
/// Called after loading a map file from disk, after the MapDoc is created but before the world is loaded.
/// This makes it the perfect place to resolve any dependent assets or game data, but not the place
/// to interact with the world in any meaningful way.
/// </summary>
internal static void PostLoadMap( MapDocument mapDoc )
{
// tony: This used to house loading all references, but we do this on project startup now, so seemed useless
}
}