LibraryStore.cs
namespace PixelPusher;
public sealed class LibraryItem
{
public string Id { get; set; }
public string Title { get; set; }
public string Kind { get; set; }
public string Type { get; set; }
public string When { get; set; }
public bool Local { get; set; } = true;
public string File { get; set; }
}
public static class LibraryStore
{
public const string TypeProject = "pxproject";
public const string TypeSprite = "pxsprite";
public const string TypeTileset = "pxtileset";
public const string TypeStage = "pxstage";
public const string KindProject = "pixel.project";
public const string KindSprite = "pixel.sprite";
public const string KindTileset = "pixel.tileset";
public const string KindStage = "pixel.stage";
public static List<LibraryItem> Items { get; } = new();
public static int Version;
public static void Refresh()
{
Items.Clear();
try
{
foreach ( var entry in Storage.GetAll( TypeProject ) )
Items.Add( FromEntry( entry, TypeProject ) );
foreach ( var entry in Storage.GetAll( TypeSprite ) )
Items.Add( FromEntry( entry, TypeSprite ) );
foreach ( var entry in Storage.GetAll( TypeTileset ) )
Items.Add( FromEntry( entry, TypeTileset ) );
foreach ( var entry in Storage.GetAll( TypeStage ) )
Items.Add( FromEntry( entry, TypeStage ) );
}
catch ( Exception e )
{
Log.Info( $"[PIXEL PUSHER] Storage list: {e.Message}" );
}
TryAddLocal( "pxproject.json", TypeProject, KindProject, "local project" );
TryAddLocal( "pxsprite.json", TypeSprite, KindSprite, "local sprite" );
TryAddLocal( "pxtileset.json", TypeTileset, KindTileset, "local tileset" );
TryAddLocal( "pxstage.json", TypeStage, KindStage, "local stage" );
for ( var i = StarterPack.Shelf.Length - 1; i >= 0; i-- )
{
var s = StarterPack.Shelf[i];
if ( Items.Exists( x => x.Id == s.Id ) )
continue;
Items.Insert( 0, new LibraryItem
{
Id = s.Id,
Title = s.Title,
Kind = s.Kind,
Type = TypeOfKind( s.Kind ),
When = s.When,
Local = true
} );
}
Version++;
GameFlow.Bump();
}
public static void SaveCurrent( string kind )
{
Desk.Autosave( quiet: true );
kind ??= TypeProject;
var title = Desk.Name ?? "untitled";
try
{
var entry = Storage.CreateEntry( kind );
switch ( kind )
{
case TypeSprite:
entry.Files.WriteJson( "sprite.json", Desk.Sprite.ToSave() );
break;
case TypeTileset:
entry.Files.WriteJson( "tileset.json", Desk.Tileset.ToSave() );
break;
case TypeStage:
entry.Files.WriteJson( "stage.json", Desk.Stage.ToSave() );
break;
default:
kind = TypeProject;
entry.Files.WriteJson( "project.json", Desk.ToSave() );
break;
}
entry.SetMeta( "title", title );
entry.SetMeta( "kind", KindOf( kind ) );
GameFlow.ShowToast( $"saved to desk · {title}" );
}
catch ( Exception e )
{
try
{
var file = kind.Replace( '.', '_' ) + ".json";
FileSystem.Data.WriteJson( file, Desk.ToSave() );
GameFlow.ShowToast( $"saved locally · {title}" );
}
catch
{
GameFlow.ShowToast( "save failed" );
Log.Warning( $"[PIXEL PUSHER] save: {e.Message}" );
}
}
Refresh();
}
public static void PublishCurrent()
{
Desk.Autosave( quiet: true );
try
{
var entry = Storage.CreateEntry( TypeProject );
entry.Files.WriteJson( "project.json", Desk.ToSave() );
entry.SetMeta( "title", Desk.Name ?? GameInfo.Title );
entry.SetMeta( "kind", KindProject );
entry.SetMeta( "rank", GameInfo.Rank );
entry.Publish();
GameFlow.ShowToast( "publish dialog opened" );
}
catch ( Exception e )
{
SaveCurrent( TypeProject );
GameFlow.ShowToast( "published locally — workshop later" );
Log.Info( $"[PIXEL PUSHER] publish: {e.Message}" );
}
Refresh();
}
public static void LoadStarter()
{
LoadShelf( "starter" );
}
public static bool LoadShelf( string id )
{
if ( !StarterPack.LoadShelf( id ) )
return false;
GameFlow.ShowToast( $"opened {Desk.Name}" );
GameFlow.Bump();
return true;
}
public static void Open( LibraryItem item )
{
if ( item is null )
return;
if ( StarterPack.LoadShelf( item.Id ) )
{
GameFlow.ShowToast( $"opened {Desk.Name}" );
if ( item.Kind == KindSprite )
GameFlow.OpenStudio( GameScreen.Pixel );
else
GameFlow.OpenStudio( GameScreen.Stage );
Refresh();
return;
}
try
{
if ( !string.IsNullOrWhiteSpace( item.File ) && FileSystem.Data.FileExists( item.File ) )
{
ApplyFile( item.Type, item.File );
return;
}
foreach ( var entry in Storage.GetAll( item.Type ) )
{
if ( entry.Id.ToString() != item.Id )
continue;
ApplyEntry( entry, item.Type );
return;
}
}
catch ( Exception e )
{
Log.Warning( $"[PIXEL PUSHER] open: {e.Message}" );
}
GameFlow.ShowToast( "could not open" );
}
static void ApplyEntry( Storage.Entry entry, string type )
{
switch ( type )
{
case TypeSprite:
Desk.Sprite = PixelDoc.FromSave( entry.Files.ReadJson<PixelSave>( "sprite.json" ) );
GameFlow.OpenStudio( GameScreen.Pixel );
break;
case TypeTileset:
Desk.Tileset = TilesetDoc.FromSave( entry.Files.ReadJson<TilesetSave>( "tileset.json" ) );
GameFlow.OpenStudio( GameScreen.Stage );
break;
case TypeStage:
Desk.Stage = StageDoc.FromSave( entry.Files.ReadJson<StageSave>( "stage.json" ) );
GameFlow.OpenStudio( GameScreen.Stage );
break;
default:
Desk.Apply( entry.Files.ReadJson<ProjectSave>( "project.json" ) );
GameFlow.OpenStudio( GameScreen.Stage );
break;
}
Desk.Touch();
GameFlow.ShowToast( $"opened · {Desk.Name}" );
Refresh();
}
static void ApplyFile( string type, string file )
{
switch ( type )
{
case TypeSprite:
Desk.Sprite = PixelDoc.FromSave( FileSystem.Data.ReadJsonOrDefault<PixelSave>( file, null ) );
GameFlow.OpenStudio( GameScreen.Pixel );
break;
case TypeTileset:
Desk.Tileset = TilesetDoc.FromSave( FileSystem.Data.ReadJsonOrDefault<TilesetSave>( file, null ) );
GameFlow.OpenStudio( GameScreen.Stage );
break;
case TypeStage:
Desk.Stage = StageDoc.FromSave( FileSystem.Data.ReadJsonOrDefault<StageSave>( file, null ) );
GameFlow.OpenStudio( GameScreen.Stage );
break;
default:
Desk.Apply( FileSystem.Data.ReadJsonOrDefault<ProjectSave>( file, null ) );
GameFlow.OpenStudio( GameScreen.Stage );
break;
}
Desk.Touch();
GameFlow.ShowToast( $"opened · {Desk.Name}" );
Refresh();
}
static void TryAddLocal( string file, string type, string kind, string when )
{
try
{
if ( !FileSystem.Data.FileExists( file ) )
return;
if ( Items.Exists( i => i.File == file ) )
return;
Items.Add( new LibraryItem
{
Id = file,
Title = file,
Kind = kind,
Type = type,
When = when,
Local = true,
File = file
} );
}
catch
{
// ignore
}
}
static LibraryItem FromEntry( Storage.Entry entry, string kind )
{
var title = "untitled";
try
{
title = entry.GetMeta( "title", title );
}
catch
{
// ignore
}
return new LibraryItem
{
Id = entry.Id.ToString(),
Title = title,
Kind = KindOf( kind ),
Type = kind,
When = entry.Created.ToString( "yyyy-MM-dd HH:mm" ),
Local = true
};
}
static string KindOf( string type ) => type switch
{
TypeSprite => KindSprite,
TypeTileset => KindTileset,
TypeStage => KindStage,
_ => KindProject
};
static string TypeOfKind( string kind ) => kind switch
{
KindSprite => TypeSprite,
KindTileset => TypeTileset,
KindStage => TypeStage,
_ => TypeProject
};
}