2024-07-19 15:24:50 +02:00
using Nerfed.Runtime ;
using System.Reflection ;
using System.Text.Json ;
namespace Nerfed.Editor.Project ;
public class ProjectConfig
{
public string Name { get ; set ; }
public uint Version { get ; set ; }
public string RuntimeProject { get ; set ; }
}
internal static class Project
{
private const string projectFileName = ".project" ;
internal static ProjectConfig LoadedConfig { get ; private set ; }
internal static string ProjectDirectory { get ; private set ; }
internal static string ProjectContentDirectory { get ; private set ; }
internal static string ProjectTempDirectory { get ; private set ; }
internal static bool Create ( string path , string projectName )
{
// Check if folder is empty.
if ( ! Directory . Exists ( path ) )
{
Directory . CreateDirectory ( path ) ;
}
if ( Directory . GetFiles ( path ) . Length ! = 0 )
{
Log . Error ( $"Directory {path} is not empty!" ) ;
return false ;
}
// Create project file.
ProjectConfig projectConfig = new ProjectConfig
{
Name = projectName ,
Version = /*Nerfed.Runtime.Verion*/ 1 ,
} ;
// Create solution.
2024-07-20 00:46:08 +02:00
GenerateSolution ( path , projectConfig ) ;
2024-07-19 15:24:50 +02:00
string projectFilePath = Path . Combine ( path , projectFileName ) ;
SaveProject ( projectFilePath , projectConfig ) ;
// Open the project.
Open ( projectFilePath ) ;
Log . Info ( $"Succesfully created project." ) ;
return true ;
}
internal static bool Open ( string path )
{
string projectFilePath = path ;
if ( ! File . Exists ( projectFilePath ) ) {
projectFilePath = Path . Combine ( path , projectFileName ) ;
if ( ! File . Exists ( projectFilePath ) )
{
Log . Error ( $"Project file not found at {path} or {projectFilePath}" ) ;
return false ;
}
}
// Load from file.
string jsonString = File . ReadAllText ( projectFilePath ) ;
ProjectConfig projectConfig = JsonSerializer . Deserialize < ProjectConfig > ( jsonString ) ;
// Check version.
if ( projectConfig . Version ! = /*Nerfed.Runtime.Verion*/ 1 )
{
Log . Error ( $"Project runtime version does not match editor runtime verion!" ) ;
return false ;
}
LoadedConfig = projectConfig ;
SetupDefaultFolders ( Path . GetDirectoryName ( projectFilePath ) ) ;
Log . Info ( $"Opened project: {projectConfig.Name}" ) ;
return true ;
}
internal static bool SaveProject ( string path , ProjectConfig projectConfig )
{
JsonSerializerOptions options = new JsonSerializerOptions ( JsonSerializerOptions . Default )
{
WriteIndented = true ,
} ;
string jsonString = JsonSerializer . Serialize ( projectConfig , options ) ;
File . WriteAllText ( path , jsonString ) ;
return true ;
}
// Compile the project using the builder.
internal static bool CompileProject ( )
{
2024-07-20 00:46:08 +02:00
//GenerateSolution();
//dotnet build <sln>
2024-07-19 15:24:50 +02:00
return false ;
}
2024-07-20 00:46:08 +02:00
private static void GenerateSolution ( string path , ProjectConfig projectConfig )
{
GenerateCSProjectFiles ( path , projectConfig ) ;
Log . Info ( "Generating solution file" ) ;
string solution =
$ @ "
Microsoft Visual Studio Solution File , Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.10 . 35013.160
MinimumVisualStudioVersion = 10.0 . 40219.1
Project ( "" { { FAE04EC0 - 301F - 11D 3 - BF4B - 00 C04F79EFBC } } "" ) = "" { projectConfig . Name } . Runtime "" , "" { projectConfig . Name } . Runtime . csproj "" , "" { { B04FAEF8 - 7D 91 - 43 A9 - 81 C5 - 4 BD3217B0C23 } } ""
EndProject
Global
GlobalSection ( SolutionConfigurationPlatforms ) = preSolution
Test | x64 = Test | x64
Release | x64 = Release | x64
Debug | x64 = Debug | x64
EndGlobalSection
GlobalSection ( ProjectConfigurationPlatforms ) = postSolution
{ { B04FAEF8 - 7D 91 - 43 A9 - 81 C5 - 4 BD3217B0C23 } } . Test | x64 . ActiveCfg = Test | x64
{ { B04FAEF8 - 7D 91 - 43 A9 - 81 C5 - 4 BD3217B0C23 } } . Test | x64 . Build . 0 = Test | x64
{ { B04FAEF8 - 7D 91 - 43 A9 - 81 C5 - 4 BD3217B0C23 } } . Release | x64 . ActiveCfg = Release | x64
{ { B04FAEF8 - 7D 91 - 43 A9 - 81 C5 - 4 BD3217B0C23 } } . Release | x64 . Build . 0 = Release | x64
{ { B04FAEF8 - 7D 91 - 43 A9 - 81 C5 - 4 BD3217B0C23 } } . Debug | x64 . ActiveCfg = Debug | x64
{ { B04FAEF8 - 7D 91 - 43 A9 - 81 C5 - 4 BD3217B0C23 } } . Debug | x64 . Build . 0 = Debug | x64
EndGlobalSection
GlobalSection ( SolutionProperties ) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection ( ExtensibilityGlobals ) = postSolution
SolutionGuid = { { 117D D74B - A4DC - 48 CE - B782 - C7AE565A9270 } }
EndGlobalSection
EndGlobal
";
string solutionName = projectConfig . Name + ".sln" ;
string filePath = Path . Combine ( path , solutionName ) ;
File . WriteAllText ( filePath , solution ) ;
}
2024-07-19 15:24:50 +02:00
// Inspirered by https://github.com/ProwlEngine/Prowl/blob/main/Prowl.Editor/Project.cs
// Maybe the builder should do this?
// When compiling the 'runtimeAssembly.Location' needs to be updated to where ever the one is that is being used.
2024-07-20 00:46:08 +02:00
private static void GenerateCSProjectFiles ( string path , ProjectConfig projectConfig )
2024-07-19 15:24:50 +02:00
{
Log . Info ( "Generating CS project files" ) ;
Assembly [ ] loadedAssemblies = AppDomain . CurrentDomain . GetAssemblies ( ) ;
Assembly runtimeAssembly = loadedAssemblies . FirstOrDefault ( assembly = > assembly . GetName ( ) . Name = = "Nerfed.Runtime" ) ? ? throw new Exception ( "Failed to find Runtime Assembly!" ) ;
string propertyGroup =
2024-07-20 00:46:08 +02:00
$ @ "
< PropertyGroup >
< TargetFramework > net8 . 0 < / TargetFramework >
< ImplicitUsings > enable < / ImplicitUsings >
< Nullable > disable < / Nullable >
< PublishAot > true < / PublishAot >
< InvariantGlobalization > true < / InvariantGlobalization >
< AllowUnsafeBlocks > true < / AllowUnsafeBlocks >
< AppendTargetFrameworkToOutputPath > false < / AppendTargetFrameworkToOutputPath >
< IsPackable > false < / IsPackable >
< Configurations > Debug ; Test ; Release < / Configurations >
< Platforms > x64 < / Platforms >
< / PropertyGroup >
< PropertyGroup Condition = "" ' $ ( Configuration ) | $ ( Platform ) ' = = ' Debug | x64 ' "" >
< DefineConstants > TRACE ; LOG_INFO ; PROFILING < / DefineConstants >
< / PropertyGroup >
< PropertyGroup Condition = "" ' $ ( Configuration ) | $ ( Platform ) ' = = ' Test | x64 ' "" >
< DefineConstants > TRACE ; LOG_ERROR ; PROFILING < / DefineConstants >
< Optimize > true < / Optimize >
< / PropertyGroup >
< PropertyGroup Condition = "" ' $ ( Configuration ) | $ ( Platform ) ' = = ' Release | x64 ' "" >
< DefineConstants > TRACE ; LOG_ERROR < / DefineConstants >
< Optimize > true < / Optimize >
< / PropertyGroup >
";
2024-07-19 15:24:50 +02:00
string runtimeProject =
2024-07-20 00:46:08 +02:00
$ @ "
< Project Sdk = "" Microsoft . NET . Sdk "" >
{ propertyGroup }
< ItemGroup >
< Compile Include = "" / Content / Scripts / Runtime /**/ * . cs "" / >
< / ItemGroup >
< ItemGroup >
< Reference Include = "" Nerfed . Runtime "" >
< HintPath > { runtimeAssembly . Location } < / HintPath >
< Private > false < / Private >
< / Reference >
< / ItemGroup >
< / Project >
";
2024-07-19 15:24:50 +02:00
string runtimeProjectName = projectConfig . Name + ".Runtime.csproj" ;
string filePath = Path . Combine ( path , runtimeProjectName ) ;
File . WriteAllText ( filePath , runtimeProject ) ;
projectConfig . RuntimeProject = runtimeProjectName ;
Log . Info ( $"Generated runtime at {filePath}" ) ;
// TODO: Editor project.
}
private static void SetupDefaultFolders ( string path )
{
ProjectDirectory = path ;
string contentPath = Path . Combine ( path , "Content" ) ;
if ( ! Directory . Exists ( contentPath ) )
{
Directory . CreateDirectory ( contentPath ) ;
}
ProjectContentDirectory = contentPath ;
2024-07-20 00:46:08 +02:00
string scriptsPath = Path . Combine ( ProjectContentDirectory , "Scripts" ) ;
if ( ! Directory . Exists ( scriptsPath ) )
{
Directory . CreateDirectory ( scriptsPath ) ;
}
string scriptsRuntimePath = Path . Combine ( scriptsPath , "Runtime" ) ;
if ( ! Directory . Exists ( scriptsRuntimePath ) )
{
Directory . CreateDirectory ( scriptsRuntimePath ) ;
}
2024-07-19 15:24:50 +02:00
string tempPath = Path . Combine ( path , "Temp" ) ;
if ( ! Directory . Exists ( tempPath ) )
{
Directory . CreateDirectory ( tempPath ) ;
}
ProjectTempDirectory = tempPath ;
}
}