Skip to content

Commit

Permalink
0.1.70 - add support for ScreenId.bytes
Browse files Browse the repository at this point in the history
  • Loading branch information
neilsarkar committed Aug 11, 2020
1 parent 88f89b6 commit 221f836
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 27 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.1.70] - 2020-08-11

### Added
- ScreenId now uses Assets/Menus/ScreenId.bytes as a persistent source of truth for package

## [0.1.69] - 2020-08-10

### Changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,30 @@
using System.Reflection;
using System.Text;
using UnityEditor;
using UnityEditor.Compilation;
using UnityEngine;

namespace VioletUI {
[InitializeOnLoad]
public class ScreenIdGenerator {
static StringBuilder sb = new StringBuilder();

static ScreenIdGenerator() {
// when unity starts up, add hook to allow Navigator to call this
Navigator.WantsRegenerate -= Generate;
Navigator.WantsRegenerate += Generate;

// read screens from .bytes file in case we lost references
var screenIds = ScreenIdSerializer.Deserialize();
Violet.LogVerbose($"Deserialized {screenIds.Count} screens");
if (screenIds == null) { return; }
bool hasNewScreens = screenIds.Exists((screenId) =>
!Enum.TryParse<ScreenId>(screenId.Item1, out _)
);
Violet.LogVerbose($"hasNewScreens={hasNewScreens}");
if (!hasNewScreens) { return; }
WriteScreenIds(screenIds);
}

public static void Generate(VioletScreen screen) {
Generate(new VioletScreen[] {screen});
}
Expand All @@ -34,41 +51,50 @@ static List<string> Filter(List<string> screens) {
var ret = new List<string>();
foreach (var screen in screens.Distinct()) {
if (screen == null) { continue; }
var name = Sanitize(screen);
var name = VioletScreen.Sanitize(screen);
if (Enum.TryParse<ScreenId>(name, out _)) { continue; }
ret.Add(name);
}
return ret;
}

static void AddVioletScreens(List<string> screens) {
sb.Clear();
sb.AppendLine("//Names are automatically added through ScreenIdGenerator.cs, deletions are done manually :)");
sb.AppendLine("namespace VioletUI {");
sb.AppendLine("\tpublic enum ScreenId {");
sb.AppendLine("\t\tNone = 0,");
// always include None as the default ScreenId
var screenIds = new List<Tuple<string, int>>() {};

// write all existing Enum values - note that unused screens
// will have to be deleted manually. this is to avoid losing references.
foreach (ScreenId screenId in Enum.GetValues(typeof(ScreenId))) {
if (screenId == ScreenId.None) { continue; }
sb.AppendLine($"\t\t{Enum.GetName(typeof(ScreenId), screenId)} = {(int)screenId},");
screenIds.Add(new Tuple<string, int>(
Enum.GetName(typeof(ScreenId), screenId), (int)screenId
));
}

// write any new screen names with incrementing ids
// write new screen names with incrementing ids
var nextId = Enum.GetValues(typeof(ScreenId)).Cast<int>().Max() + 1;
foreach (var screen in screens) {
sb.AppendLine($"\t\t{screen} = {nextId++},");
screenIds.Add(new Tuple<string, int>(
screen, nextId++
));
}

WriteScreenIds(screenIds);
}

static void WriteScreenIds(List<Tuple<string, int>> screenIds) {
sb.Clear();
sb.AppendLine("//Names are automatically added through ScreenIdGenerator.cs, deletions are done manually :)");
sb.AppendLine("namespace VioletUI {");
sb.AppendLine("\tpublic enum ScreenId {");
foreach (var screenId in screenIds) {
sb.AppendLine($"\t\t{screenId.Item1} = {screenId.Item2},");
}
sb.AppendLine("\t}");
sb.AppendLine("}");
File.WriteAllText(packagePath(), sb.ToString());
Violet.Log("Regenerating the ScreenId enum, this may take a second to recompile.");
AssetDatabase.Refresh();
}

public static string Sanitize(string s) {
return s.Replace(" ", "");
ScreenIdSerializer.Serialize(screenIds);
}

static string packagePath() {
Expand Down
File renamed without changes.
51 changes: 51 additions & 0 deletions Editor/ScreenIdSerializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace VioletUI {
/// <summary>
/// ScreenIdSerializer is used as a workaround for enum generation with package updating.
///
/// Since the enum is kept in the package folder and the package folder is deleted on upgrade,
/// we need a way of storing the enum to a file and then reading it back out
///
/// Storing and copying a .cs file wouldn't work since it would cause compile errors when the file was duplicated.
/// </summary>
public class ScreenIdSerializer {
public static void Serialize() {
// put enum into a list of strings and ints
List<Tuple<string, int>> screenIds = new List<Tuple<string, int>>();
foreach (ScreenId screenId in Enum.GetValues(typeof(ScreenId))) {
screenIds.Add(new Tuple<string, int>(
Enum.GetName(typeof(ScreenId), screenId), (int)screenId
));
}
Serialize(screenIds);
}

public static void Serialize(List<Tuple<string, int>> screenIds) {
// create menu if it doesn't exist
if (!Directory.Exists("Assets/Menus")) {
Directory.CreateDirectory("Assets/Menus");
}

// serialize tuples to binary file
var formatter = new BinaryFormatter();
using(var fs = new FileStream("Assets/Menus/ScreenIds.bytes", FileMode.Create)) {
formatter.Serialize(fs, screenIds);
}
}


public static List<Tuple<string, int>> Deserialize() {
var formatter = new BinaryFormatter();
List<Tuple<string, int>> screenIds;
if (!File.Exists("Assets/Menus/ScreenIds.bytes")) { return null; }
using(var fs = new FileStream("Assets/Menus/ScreenIds.bytes", FileMode.Open)) {
screenIds = formatter.Deserialize(fs) as List<Tuple<string, int>>;
}
return screenIds;
}
}
}
11 changes: 11 additions & 0 deletions Editor/ScreenIdSerializer.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 11 additions & 10 deletions Runtime/Navigation/Navigator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
using Sirenix.OdinInspector;
using System.Threading;
using UniRx.Async;
#if UNITY_EDITOR
using UnityEngine.UI;
#if UNITY_EDITOR
using UnityEditor;
#endif

Expand Down Expand Up @@ -139,7 +139,7 @@ protected virtual void VisitFirstScreen() {

ScreenId ScreenToScreenId(VioletScreen screen) {
ScreenId ret;
var slug = ScreenIdGenerator.Sanitize(screen.name);
var slug = VioletScreen.Sanitize(screen.name);
var ok = Enum.TryParse<ScreenId>(slug, out ret);

if (!ok) {
Expand All @@ -148,17 +148,18 @@ ScreenId ScreenToScreenId(VioletScreen screen) {
return ret;
}


void LoadScreens() {
if (transform.childCount == 0) { return; }

ScreenId screenId = ScreenId.None;
screens.Clear();
foreach (VioletScreen screen in GetComponentsInChildren<VioletScreen>(true)) {
var isValid = Enum.TryParse(ScreenIdGenerator.Sanitize(screen.name), out screenId);
var isValid = Enum.TryParse(VioletScreen.Sanitize(screen.name), out screenId);
if (!isValid) {
#if UNITY_EDITOR
Violet.LogWarning($"Couldn't find {screen.name}, regenerating. Try pressing play again. ScreenId contains {string.Join(", ", Enum.GetNames(typeof(ScreenId)))}");
RegenerateEnums();
Violet.LogWarning($"Couldn't find {screen.name}, regenerating. Try pressing play again. ScreenId contains {string.Join(", ", Enum.GetNames(typeof(ScreenId)))}");
#if UNITY_EDITOR
EditorApplication.ExitPlaymode();
#else
throw new VioletException($"{screen.name} does not have a valid ScreenId. ScreenId contains {string.Join(", ", Enum.GetNames(typeof(ScreenId)))}"");
Expand Down Expand Up @@ -222,7 +223,7 @@ public void AddScreen() {
gameObject.AddComponent<GraphicRaycaster>();
gameObject.transform.SetParent(transform, false);
gameObject.transform.position = new Vector3(0, 0, 0);
gameObject.transform.localScale = new Vector3(1,1,1);
gameObject.transform.localScale = new Vector3(1, 1, 1);

if (hasCamera) {
canvas.renderMode = RenderMode.ScreenSpaceCamera;
Expand All @@ -234,7 +235,7 @@ public void AddScreen() {
EditingScreen = screen;
}

protected virtual void OnScreenAdded(GameObject gameObject) {}
protected virtual void OnScreenAdded(GameObject gameObject) { }

float lastUpdate;
int childCount;
Expand All @@ -260,10 +261,10 @@ void Regenerate() {
Violet.LogVerbose($"Done reloading screens.");
}

// TODO: move all of this to the editor assembly
public static Action<VioletScreen[]> WantsRegenerate;
void RegenerateEnums() {
var screens = GetComponentsInChildren<VioletScreen>(true);
ScreenIdGenerator.Generate(screens);
Violet.LogVerbose($"Done regenerating enums.");
WantsRegenerate?.Invoke(GetComponentsInChildren<VioletScreen>(true));
}
#endif
}
Expand Down
5 changes: 4 additions & 1 deletion Runtime/Navigation/VioletScreen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,12 @@ public void Update() {
EditorSceneManager.sceneSaved += EditorSceneManager_sceneSaved;
}

// [SerializeField, HideInInspector]
string prefabPath = "";

public static string Sanitize(string s) {
return s.Replace(" ", "");
}

public void PackPrefab() {
var path = string.IsNullOrEmpty(prefabPath) ? $"Assets/Menus/{name}.prefab" : prefabPath;
PrefabUtility.SaveAsPrefabAssetAndConnect(gameObject, path, InteractionMode.AutomatedAction);
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "com.neilsarkar.violetui",
"version": "0.1.69",
"version": "0.1.70",
"displayName": "Violet UI",
"description": "State-based rendering with live updates in the Unity Editor",
"unity": "2019.4",
Expand Down

0 comments on commit 221f836

Please sign in to comment.