diff --git a/Assets/RothenburgAR/Editor/Test/PoiXmlPreloaderTest.cs b/Assets/RothenburgAR/Editor/Test/PoiXmlPreloaderTest.cs index 200d97a..35283f7 100644 --- a/Assets/RothenburgAR/Editor/Test/PoiXmlPreloaderTest.cs +++ b/Assets/RothenburgAR/Editor/Test/PoiXmlPreloaderTest.cs @@ -83,9 +83,10 @@ namespace RothenburgAR poiXmlPreloader = new PoiXmlPreloader(); - PoiData poiData = poiXmlPreloader.PreloadPoi(testDirectory); + List poiData = poiXmlPreloader.PreloadPoi(testDirectory); Assert.NotNull(poiData); - Assert.AreEqual("testPoi", poiData.ID); + Assert.NotZero(poiData.Count); + Assert.AreEqual("testPoi", poiData[0].ID); } private void WriteTestPng(string path) diff --git a/Assets/RothenburgAR/Scripts/AppInitializerBehaviour.cs b/Assets/RothenburgAR/Scripts/AppInitializerBehaviour.cs index 7fcb415..aa38c80 100644 --- a/Assets/RothenburgAR/Scripts/AppInitializerBehaviour.cs +++ b/Assets/RothenburgAR/Scripts/AppInitializerBehaviour.cs @@ -33,10 +33,16 @@ namespace RothenburgAR { PoiDataManager.Instance.AddPoiDataSourcePath(PathHelper.POIPath); PoiDataManager.Instance.AddPoiPreloader(new PoiXmlPreloader()); + + PoiDataManager.Instance.AddPoiDataSourcePath(PathHelper.ExhibitionPath); + PoiDataManager.Instance.AddPoiPreloader(new PoiJsonPreloader()); + PoiDataManager.Instance.LoadEverySourcePath(); ExhibitionManager.Instance.AddExhibitionSourcePath(PathHelper.ExhibitionPath); ExhibitionManager.Instance.AddExhibitionPreloader(new ExhibitionXmlPreloader()); + ExhibitionManager.Instance.AddExhibitionPreloader(new ExhibitionJsonPreloader()); + ExhibitionManager.Instance.LoadEverySourcePath( (int maxPaths, int currentPaths, int subMaxExhibitions, int subCurrentExhibition) => { diff --git a/Assets/RothenburgAR/Scripts/Exhibition/ExhibitionJsonPreloader.cs b/Assets/RothenburgAR/Scripts/Exhibition/ExhibitionJsonPreloader.cs new file mode 100644 index 0000000..1071d9b --- /dev/null +++ b/Assets/RothenburgAR/Scripts/Exhibition/ExhibitionJsonPreloader.cs @@ -0,0 +1,190 @@ +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Xml; +using RothenburgAR.Common; +using UnityEngine; + + +namespace RothenburgAR.Exhibition +{ + public class ExhibitionJsonPreloader : IExhibitionPreloader + { + public bool CanLoadExhibitionDirectory(string exhibitionDirectory) + { + return false; + if (!Directory.Exists(exhibitionDirectory)) + return false; + + string xmlFilePath = PathHelper.GetXmlPathFromDirectoryPath(exhibitionDirectory); + + if (!File.Exists(xmlFilePath)) + return false; + if (!File.Exists(Path.Combine(exhibitionDirectory, "tracker.xml"))) + return false; + if (!File.Exists(Path.Combine(exhibitionDirectory, "tracker.dat"))) + return false; + + // Todo: More validations + return true; + } + + public PreloadedExhibition PreloadExhibition(string exhibitionDirectory) + { + throw new System.NotImplementedException(); + string xmlFilePath = PathHelper.GetXmlPathFromDirectoryPath(exhibitionDirectory); + + if (!File.Exists(xmlFilePath)) + throw new FileNotFoundException(xmlFilePath); + + XmlDocument doc = new XmlDocument(); + doc.Load(xmlFilePath); + + // Read the ID from the xml + if (doc.DocumentElement == null || doc.DocumentElement.Attributes == null || + doc.DocumentElement.Attributes["id"] == null) + throw new InvalidXMLException("Could not read doc.DocumentElement.Attributes['id] "); + + string exhibitionId = doc.DocumentElement.Attributes["id"].Value; + + PreloadedExhibition resultExhibition = new PreloadedExhibition + { + ContainedExhibits = new List(), + ID = exhibitionId, + DatasetPath = exhibitionDirectory + }; + + var exhibitNodes = doc.SelectNodes("//exhibition/exhibit"); + foreach (XmlNode exhibitNode in exhibitNodes) + { + if (exhibitNode.Attributes == null || exhibitNode.Attributes["id"] == null) + { + // Todo: Log error + continue; + } + + var newExhibit = PreloadExhibit(exhibitionDirectory, exhibitNode); + resultExhibition.ContainedExhibits.Add(newExhibit); + } + return resultExhibition; + } + + private PreloadedExhibit PreloadExhibit(string exhibitionDirectory, XmlNode exhibitNode) + { + PreloadedExhibit newExhibit = new PreloadedExhibit(); + newExhibit.ID = exhibitNode.Attributes["id"].Value; + newExhibit.ReferencedPoiEntries = new List(); + + // Load Description Text + XmlNodeList descrList = exhibitNode.SelectNodes("description/text"); + if (descrList != null && descrList.Count > 0) + { + TextElement exhibitDescr = TextElement.BuildFromXmlNode(exhibitionDirectory, descrList); + newExhibit.Description = exhibitDescr; + } + + // Load Title Text + XmlNodeList titleList = exhibitNode.SelectNodes("title/text"); + if (titleList != null && titleList.Count > 0) + { + TextElement exhibitTitle = TextElement.BuildFromXmlNode(exhibitionDirectory, titleList); + var fontSize = GetFloatFromXmlNode(exhibitNode.SelectSingleNode("title/font"), "size"); + var boxHeight = GetFloatFromXmlNode(exhibitNode.SelectSingleNode("title/dimensions"), "height"); + var boxWidth = GetFloatFromXmlNode(exhibitNode.SelectSingleNode("title/dimensions"), "width"); + + PreloadedExhibitTitle preTitle = new PreloadedExhibitTitle + { + Text = exhibitTitle, + Position = GetVector3FromXmlNode(exhibitNode.SelectSingleNode("title/position")), + Rotation = GetVector3FromXmlNode(exhibitNode.SelectSingleNode("title/rotation")), + FontSize = fontSize ?? 20, + BoxWidth = boxWidth ?? 200, + BoxHeight = boxHeight ?? 25 + }; + newExhibit.Title = preTitle; + } + + + // Load POI References + XmlNodeList poiRefList = exhibitNode.SelectNodes("poiList/poi"); + if (poiRefList != null && poiRefList.Count > 0) + { + foreach (XmlNode poiRefEntry in poiRefList) + { + if (poiRefEntry.Attributes == null || poiRefEntry.Attributes["ref-id"] == null) + continue; + + PreloadedPoiReference poiReference = + new PreloadedPoiReference + { + ReferencedId = poiRefEntry.Attributes["ref-id"].Value, + Position = GetVector3FromXmlNode(poiRefEntry.SelectSingleNode("position")), + Rotation = GetVector3FromXmlNode(poiRefEntry.SelectSingleNode("rotation")), + Scale = GetVector3FromXmlNode(poiRefEntry.SelectSingleNode("scale")) + }; + + newExhibit.ReferencedPoiEntries.Add(poiReference); + } + } + return newExhibit; + } + + private string GetStringFromXmlNode(XmlNode node, string key) + { + if (node == null) + return null; + if (node.Attributes == null) + return null; + if (node.Attributes[key] == null) + return null; + + return node.Attributes[key].Value; + } + + private float? GetFloatFromXmlNode(XmlNode node, string key) + { + var str = GetStringFromXmlNode(node, key); + if (str == null) + return null; + try + { + return float.Parse(str, CultureInfo.InvariantCulture.NumberFormat); + } + catch + { + return null; + } + } + + private Vector3? GetVector3FromXmlNode(XmlNode node) + { + if (node == null) + return null; + if (node.Attributes == null) + return null; + if (node.Attributes["x"] == null) + return null; + if (node.Attributes["y"] == null) + return null; + if (node.Attributes["z"] == null) + return null; + + try + { + float posX = float.Parse(node.Attributes["x"].Value, + CultureInfo.InvariantCulture.NumberFormat); + float posY = float.Parse(node.Attributes["y"].Value, + CultureInfo.InvariantCulture.NumberFormat); + float posZ = float.Parse(node.Attributes["z"].Value, + CultureInfo.InvariantCulture.NumberFormat); + + return new Vector3(posX, posY, posZ); + } + catch + { + // TODO: log error + return null; + } + } + } +} \ No newline at end of file diff --git a/Assets/RothenburgAR/Scripts/Exhibition/ExhibitionJsonPreloader.cs.meta b/Assets/RothenburgAR/Scripts/Exhibition/ExhibitionJsonPreloader.cs.meta new file mode 100644 index 0000000..ca9646a --- /dev/null +++ b/Assets/RothenburgAR/Scripts/Exhibition/ExhibitionJsonPreloader.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 7806b799db63ba3468e962aea10b2549 +timeCreated: 1537892587 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RothenburgAR/Scripts/PointOfInterest/IPoiPreloader.cs b/Assets/RothenburgAR/Scripts/PointOfInterest/IPoiPreloader.cs index f8e91ce..0565284 100644 --- a/Assets/RothenburgAR/Scripts/PointOfInterest/IPoiPreloader.cs +++ b/Assets/RothenburgAR/Scripts/PointOfInterest/IPoiPreloader.cs @@ -1,8 +1,10 @@ -namespace RothenburgAR.PointOfInterest +using System.Collections.Generic; + +namespace RothenburgAR.PointOfInterest { public interface IPoiPreloader { bool CanLoadPoiDirectory(string poiDirectory); - PoiData PreloadPoi(string poiDirectory); + List PreloadPoi(string poiDirectory); } } \ No newline at end of file diff --git a/Assets/RothenburgAR/Scripts/PointOfInterest/POIDataManager.cs b/Assets/RothenburgAR/Scripts/PointOfInterest/POIDataManager.cs index 418ada2..65d0087 100644 --- a/Assets/RothenburgAR/Scripts/PointOfInterest/POIDataManager.cs +++ b/Assets/RothenburgAR/Scripts/PointOfInterest/POIDataManager.cs @@ -74,8 +74,11 @@ namespace RothenburgAR.PointOfInterest } try { - var newPoi = preloader.PreloadPoi(path); - AddPoiData(newPoi); + var newPois = preloader.PreloadPoi(path); + foreach (var newPoi in newPois) + { + AddPoiData(newPoi); + } } catch (Exception e) { diff --git a/Assets/RothenburgAR/Scripts/PointOfInterest/PoiJsonPreloader.cs b/Assets/RothenburgAR/Scripts/PointOfInterest/PoiJsonPreloader.cs new file mode 100644 index 0000000..4b27089 --- /dev/null +++ b/Assets/RothenburgAR/Scripts/PointOfInterest/PoiJsonPreloader.cs @@ -0,0 +1,122 @@ +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Xml; +using RothenburgAR.Common; +using UnityEngine; + +namespace RothenburgAR.PointOfInterest +{ + public class PoiJsonPreloader : IPoiPreloader + { + public bool CanLoadPoiDirectory(string poiDirectory) + { + //TODO remove + return false; + + if (!Directory.Exists(poiDirectory)) + return false; + + var languageDirs = Directory.GetDirectories(poiDirectory).ToList(); + foreach (var dir in languageDirs) + { + var metaFilePath = PathHelper.CombinePaths(poiDirectory, dir, "meta.json"); + if (!File.Exists(metaFilePath)) return false; + } + + // Todo: More validations + + return true; + } + + public List PreloadPoi(string poiDirectory) + { + throw new System.NotImplementedException(); + string xmlFilePath = PathHelper.GetXmlPathFromDirectoryPath(poiDirectory); + + if (!File.Exists(xmlFilePath)) + throw new FileNotFoundException(xmlFilePath); + + XmlDocument doc = new XmlDocument(); + doc.Load(xmlFilePath); + + + // Read the ID from the xml + if (doc.DocumentElement == null || doc.DocumentElement.Attributes == null || + doc.DocumentElement.Attributes["id"] == null) + throw new InvalidXMLException("Could not read doc.DocumentElement.Attributes['id] "); + + string poiId = doc.DocumentElement.Attributes["id"].Value; + + // Read the description from the xml + XmlNodeList descNodes = doc.SelectNodes("//poi/description/text"); + TextElement descElement = TextElement.BuildFromXmlNode(poiDirectory, descNodes); + + // Read the title from the xml + XmlNodeList titleNodes = doc.SelectNodes("//poi/title/text"); + TextElement titleElement = TextElement.BuildFromXmlNode(poiDirectory, titleNodes); + + + PoiData poiData = new PoiData + { + ID = poiId, + Description = descElement, + Title = titleElement, + SourcePath = poiDirectory + }; + + // Read the model value + XmlNode modelNode = doc.SelectSingleNode("//poi/model"); + if (modelNode != null) + { + var pathNode = modelNode.SelectSingleNode("path"); + var scaleNode = modelNode.SelectSingleNode("scale"); + var rotationNode = modelNode.SelectSingleNode("rotation"); + var positionNode = modelNode.SelectSingleNode("position"); + + var poiModelDescription = new PoiModelDescription + { + ModelPath = Path.Combine(poiDirectory, pathNode.Attributes["value"].Value), + ModelPrefabName = pathNode.Attributes["prefabName"].Value, + Scale = GetVector3FromXmlNode(scaleNode).GetValueOrDefault(Vector3.one), + Rotation = GetVector3FromXmlNode(rotationNode).GetValueOrDefault(Vector3.zero), + Position = GetVector3FromXmlNode(positionNode).GetValueOrDefault(Vector3.zero) + }; + poiData.ModelDescription = poiModelDescription; + } + return new List { poiData }; + } + + private Vector3? GetVector3FromXmlNode(XmlNode node) + { + if (node == null) + return null; + if (node.Attributes == null) + return null; + if (node.Attributes["x"] == null) + return null; + if (node.Attributes["y"] == null) + return null; + if (node.Attributes["z"] == null) + return null; + + try + { + float posX = float.Parse(node.Attributes["x"].Value, + CultureInfo.InvariantCulture.NumberFormat); + float posY = float.Parse(node.Attributes["y"].Value, + CultureInfo.InvariantCulture.NumberFormat); + float posZ = float.Parse(node.Attributes["z"].Value, + CultureInfo.InvariantCulture.NumberFormat); + + return new Vector3(posX, posY, posZ); + } + catch + { + // TODO: log error + return null; + } + } + } +} \ No newline at end of file diff --git a/Assets/RothenburgAR/Scripts/PointOfInterest/PoiJsonPreloader.cs.meta b/Assets/RothenburgAR/Scripts/PointOfInterest/PoiJsonPreloader.cs.meta new file mode 100644 index 0000000..87f5a0e --- /dev/null +++ b/Assets/RothenburgAR/Scripts/PointOfInterest/PoiJsonPreloader.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 65621f7647a1d0a40870d6e20203b6b9 +timeCreated: 1537892587 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/RothenburgAR/Scripts/PointOfInterest/PoiXmlPreloader.cs b/Assets/RothenburgAR/Scripts/PointOfInterest/PoiXmlPreloader.cs index 7307d7c..323e8a9 100644 --- a/Assets/RothenburgAR/Scripts/PointOfInterest/PoiXmlPreloader.cs +++ b/Assets/RothenburgAR/Scripts/PointOfInterest/PoiXmlPreloader.cs @@ -1,4 +1,5 @@ -using System.Globalization; +using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Xml; using RothenburgAR.Common; @@ -23,7 +24,7 @@ namespace RothenburgAR.PointOfInterest return true; } - public PoiData PreloadPoi(string poiDirectory) + public List PreloadPoi(string poiDirectory) { string xmlFilePath = PathHelper.GetXmlPathFromDirectoryPath(poiDirectory); @@ -77,7 +78,7 @@ namespace RothenburgAR.PointOfInterest }; poiData.ModelDescription = poiModelDescription; } - return poiData; + return new List { poiData }; } private Vector3? GetVector3FromXmlNode(XmlNode node) diff --git a/Assets/RothenburgAR/Scripts/Updater/ApiInfo.cs b/Assets/RothenburgAR/Scripts/Updater/ApiInfo.cs index 63a6f82..e2d41ef 100644 --- a/Assets/RothenburgAR/Scripts/Updater/ApiInfo.cs +++ b/Assets/RothenburgAR/Scripts/Updater/ApiInfo.cs @@ -31,9 +31,11 @@ namespace RothenburgAR.Updater [Serializable] public class VersioncheckAnswer { - [JsonProperty] - public List languages { get; set; } - public List data { get; set; } + [JsonProperty("languages")] + public List Languages { get; set; } + + [JsonProperty("data")] + public List Data { get; set; } } [Serializable] diff --git a/Assets/RothenburgAR/Scripts/Updater/UpdaterBehaviour.cs b/Assets/RothenburgAR/Scripts/Updater/UpdaterBehaviour.cs index 88ca5e3..2c8f209 100644 --- a/Assets/RothenburgAR/Scripts/Updater/UpdaterBehaviour.cs +++ b/Assets/RothenburgAR/Scripts/Updater/UpdaterBehaviour.cs @@ -79,7 +79,7 @@ namespace RothenburgAR.Updater var answer = VersionAnswer; - if (answer.data.TrueForAll(d => d.Meta.Status == VersionStatus.ok && d.Tracker.Status == VersionStatus.ok)) + if (answer.Data.TrueForAll(d => d.Meta.Status == VersionStatus.ok && d.Tracker.Status == VersionStatus.ok)) { // no updates required, continue to app LoadMainScene(); @@ -159,8 +159,8 @@ namespace RothenburgAR.Updater //TODO write languages to file the app can read (so that the languagemanager can decide which languages the user can choose from) - var updatedMeta = VersionAnswer.data.Where(d => d.Meta.Status == VersionStatus.updated).ToList(); - var updatedTracker = VersionAnswer.data.Where(d => d.Tracker.Status == VersionStatus.updated).ToList(); + var updatedMeta = VersionAnswer.Data.Where(d => d.Meta.Status == VersionStatus.updated).ToList(); + var updatedTracker = VersionAnswer.Data.Where(d => d.Tracker.Status == VersionStatus.updated).ToList(); updatedMeta.Union(updatedTracker).ToList().ForEach(updatedExhibition => { // create exhibition directories @@ -174,7 +174,7 @@ namespace RothenburgAR.Updater updatedMeta.ForEach(d => UpdateMeta(d)); updatedTracker.ForEach(d => UpdateTracker(d)); - var deletedData = VersionAnswer.data.Where(d => + var deletedData = VersionAnswer.Data.Where(d => d.Meta.Status == VersionStatus.deleted || d.Tracker.Status == VersionStatus.deleted).ToList(); deletedData.ForEach(d => DeleteExhibition(d)); @@ -188,7 +188,7 @@ namespace RothenburgAR.Updater private void UpdateMeta(ExhibitionVersion exhibition) { - foreach (var lang in VersionAnswer.languages) + foreach (var lang in VersionAnswer.Languages) { var path = PathHelper.CombinePaths(PathHelper.ExhibitionPath, exhibition.Id, lang); var url = exhibition.Meta.UpdateUrl.Replace("{lang}", lang);