/// <summary> /// Creates and loads a new .utmodule /// @NOTE The module only exists in memory until Save() is called /// </summary> public static void NewModule() { var context = new UTinyContext(); var registry = context.Registry; UTinyPersistence.LoadAllModules(registry); // Create a `workspace` project to host the module for editing purposes var project = registry.CreateProject(UTinyId.Generate(KWorkspaceProjectName), KWorkspaceProjectName); // Create objects for the new module var module = registry.CreateModule(UTinyId.New(), "NewModule"); // Setup initial state for the module module.Namespace = "module"; SetupModule(registry, module); project.Module = (UTinyModule.Reference)module; var workspace = new UTinyEditorWorkspace(); UTinyEditorPrefs.SaveWorkspace(workspace); var editorContext = new UTinyEditorContext((UTinyProject.Reference)project, EditorContextType.Module, context, workspace); LoadContext(editorContext, isChanged: true); }
/// <summary> /// Creates and loads a new .utproject /// @NOTE The project only exists in memory until Save() is called /// </summary> public static void NewProject() { Assert.IsFalse(EditorApplication.isPlayingOrWillChangePlaymode); var context = new UTinyContext(); var registry = context.Registry; UTinyPersistence.LoadAllModules(registry); // Create new objects for the project var project = registry.CreateProject(UTinyId.New(), "NewProject"); var module = registry.CreateModule(UTinyId.New(), "Main"); // Setup the start scene var entityGroup = registry.CreateEntityGroup(UTinyId.New(), "NewEntityGroup"); var entityGroupRef = (UTinyEntityGroup.Reference)entityGroup; var cameraEntity = registry.CreateEntity(UTinyId.New(), "Camera"); var transform = cameraEntity.AddComponent(registry.GetTransformType()); transform.Refresh(); var camera = cameraEntity.AddComponent(registry.GetCamera2DType()); camera.Refresh(); camera["clearFlags"] = new UTinyEnum.Reference(registry.GetCameraClearFlagsType().Dereference(registry), 1); camera.AssignPropertyFrom("backgroundColor", Color.black); camera["depth"] = -1.0f; entityGroup.AddEntityReference((UTinyEntity.Reference)cameraEntity); // Setup initial state for the project module.Options |= UTinyModuleOptions.ProjectModule; module.Namespace = "game"; module.StartupEntityGroup = (UTinyEntityGroup.Reference)entityGroup; module.AddEntityGroupReference(entityGroupRef); project.Module = (UTinyModule.Reference)module; project.Settings.EmbedAssets = true; project.Settings.CanvasWidth = 1920; project.Settings.CanvasHeight = 1080; SetupProject(registry, project); module.AddExplicitModuleDependency((UTinyModule.Reference)registry.FindByName <UTinyModule>("UTiny.Core2D")); // Always include a dependency on core, math, core2d by default // And HTML for now, since it is the only renderer we have right now. module.AddExplicitModuleDependency((UTinyModule.Reference)registry.FindByName <UTinyModule>("UTiny.HTML")); var workspace = new UTinyEditorWorkspace { OpenedEntityGroups = { entityGroupRef }, ActiveEntityGroup = entityGroupRef }; UTinyEditorPrefs.SaveWorkspace(workspace); var editorContext = new UTinyEditorContext((UTinyProject.Reference)project, EditorContextType.Project, context, workspace); LoadContext(editorContext, isChanged: true); }
/// <summary> /// Packages assets to `assets.js` or `Assets/*.*` /// </summary> private static void PackageAssets(UTinyBuildOptions options, UTinyBuildResults results) { var buildFolder = options.Destination; var binFolder = results.BinaryFolder; // Export assets to the build directory var buildAssetsFolder = new DirectoryInfo(Path.Combine(buildFolder.FullName, "Assets")); buildAssetsFolder.Create(); var export = UTinyAssetExporter.Export(options.Project, buildAssetsFolder); // copy assets to bin AND/OR encode assets to 'assets.js' var binAssetsFolder = new DirectoryInfo(Path.Combine(binFolder.FullName, "Assets")); binAssetsFolder.Create(); var assetsFile = new FileInfo(Path.Combine(binFolder.FullName, KAssetsFileName)); var writer = new UTinyCodeWriter(); PrependGeneratedHeader(writer, options.Project.Name); var reportAssets = results.BuildReport.AddChild(UTinyBuildReport.AssetsNode); var reportJavaScript = reportAssets.AddChild("JavaScript"); using (var jsdoc = new UTinyJsdoc.Writer(writer)) { jsdoc.Type("object"); jsdoc.Desc("Map containing URLs for all assets. If assets are included as base64 blobs, these will be data URLs."); jsdoc.Line("@example var assetUrl = UT_ASSETS[\"MyCustomAsset\"]"); } long totalBase64Size = 0; using (writer.Scope("var UT_ASSETS =")) { var i = 0; foreach (var info in export) { var reportAsset = reportAssets.AddChild(info.AssetInfo.AssetPath, 0, info.AssetInfo.Object); var settings = UTinyUtility.GetAssetExportSettings(options.Project, info.AssetInfo.Object); if (settings.Embedded) { foreach (var file in info.Exported) { var buffer = File.ReadAllBytes(file.FullName); var base64 = Convert.ToBase64String(buffer); var fileExtension = Path.GetExtension(file.FullName).ToLower(); string mimeType; switch (fileExtension) { case ".png": mimeType = "image/png"; break; case ".jpg": case ".jpeg": mimeType = "image/jpeg"; break; case ".webp": mimeType = "image/webp"; break; case ".mp3": mimeType = "audio/mpeg"; break; case ".wav": mimeType = "audio/wav"; break; case ".json": mimeType = "application/json"; break; case ".ttf": mimeType = "font/truetype"; break; default: Debug.LogWarningFormat("Asset {0} has unknown extension, included as text/plain in assets", file); mimeType = "text/plain"; break; } var comma = i != 0 ? "," : ""; writer.Line($"{comma}\"{Path.GetFileNameWithoutExtension(file.Name)}\": \"data:{mimeType};base64,{base64}\""); i++; reportAsset.AddChild(UTinyBuildPipeline.GetRelativePath(file), Encoding.ASCII.GetBytes(base64), info.AssetInfo.Object); totalBase64Size += base64.Length; file.Delete(); } } else { foreach (var file in info.Exported) { var comma = i != 0 ? "," : ""; writer.Line($"{comma}\"{Path.GetFileNameWithoutExtension(file.Name)}\": \"Assets/{file.Name}\""); i++; reportAsset.AddChild(file, info.AssetInfo.Object); } } } } writer.Line(); writer.WriteRaw("var UT_ASSETS_SETUP = "); { var registry = new UTinyRegistry(); UTinyPersistence.LoadAllModules(registry); var entityGroup = UTinyAssetEntityGroupGenerator.Generate(registry, options.Project); EntityGroupSetupVisitor.WriteEntityGroupSetupFunction(writer, options.Project, entityGroup, false, false); } // Write `assets.js` File.WriteAllText(assetsFile.FullName, writer.ToString()); reportJavaScript.Item.Size = assetsFile.Length - totalBase64Size; // Remaining assets are binplaced foreach (var info in export) { foreach (var file in info.Exported) { if (!file.Exists) { // this asset has been packaged already continue; } file.MoveTo(Path.Combine(binAssetsFolder.FullName, file.Name)); } } // Clean up the build directory buildAssetsFolder.Delete(true); // if we have no standalone assets, cleanup if (binAssetsFolder.GetFiles().Length <= 0) { binAssetsFolder.Delete(); } }
/// <summary> /// @TODO This method has too many conditionals and checks... it should be managed at a higher level /// </summary> /// <param name="registry"></param> /// <param name="persistenceId"></param> /// <returns></returns> /// <exception cref="ArgumentOutOfRangeException"></exception> public static bool Accept(IRegistry registry, out string persistenceId) { Assert.IsTrue(Exists()); registry.Clear(); UTinyPersistence.LoadAllModules(registry); registry.UnregisterAllBySource(UTinyRegistry.DefaultSourceIdentifier); persistenceId = null; using (var command = new MemoryStream()) using (var stream = File.OpenRead(GetTempLocation().FullName)) using (var reader = new BinaryReader(stream)) using (registry.SourceIdentifierScope(UTinyRegistry.DefaultSourceIdentifier)) { var version = reader.ReadInt32(); Assert.IsTrue(version > 0); var type = (SaveType)reader.ReadByte(); switch (type) { case SaveType.PersistentUnchanged: persistenceId = reader.ReadString(); return(false); case SaveType.PersistentChanged: persistenceId = reader.ReadString(); var hash = reader.ReadString(); if (!string.IsNullOrEmpty(hash) && !string.Equals(hash, ComputeHash(persistenceId))) { // Ask the user if they want to keep their changes or reload from disc if (EditorUtility.DisplayDialog($"{UTinyConstants.ApplicationName} assets changed", $"{UTinyConstants.ApplicationName} assets have changed on disk, would you like to reload the current project?", "Yes", "No")) { return(false); } } break; case SaveType.Temporary: break; default: throw new ArgumentOutOfRangeException(); } // This is to handle module editing. // We want to unregister it from its current source and re-register it with the persistenceId as the scope if (!string.IsNullOrEmpty(persistenceId)) { registry.UnregisterAllBySource(persistenceId); } FrontEnd.Accept(stream, command); command.Position = 0; Serialization.CommandStream.FrontEnd.Accept(command, registry); } foreach (var project in registry.FindAllBySource(UTinyRegistry.DefaultSourceIdentifier).OfType <UTinyProject>()) { project.PersistenceId = persistenceId; } return(true); }