/// <summary> /// Calculate the checksum for a LEGO Universe zone /// </summary> /// <param name="zone">Path to zone file</param> /// <returns>Calculated checksum</returns> public static uint Generate(string zone) { uint value = ushort.MaxValue; // For checksum calculations uint total = ushort.MaxValue; // Sum of all changes applied to value // // Read zone file // var luz = new LuzFile(); using (var stream = File.OpenRead(zone)) { using var reader = new BitReader(stream); luz.Deserialize(reader); } // // Apply zone layer // var zoneLayer = new ChecksumLayer { Id = uint.MaxValue, Layer = default,
public static uint GenerateChecksum(this LuzFile @this, List <LvlFile> scenes) { if (@this.Scenes.Length != scenes.Count) { throw new ArgumentOutOfRangeException(nameof(scenes), "The count of scenes has to equal the count of scenes in this luz file."); } uint value = ushort.MaxValue; // For checksum calculations uint total = ushort.MaxValue; // Sum of all changes applied to value var zoneLayer = new ChecksumLayer { Id = uint.MaxValue, Layer = default,
public async Task SaveAsync(string path) { var file = new LuzFile { TerrainFile = Terrain.Name, TerrainFileName = Terrain.FileName, TerrainDescription = Terrain.Description, Version = 0x26, SpawnPoint = SpawnPosition, SpawnRotation = SpawnRotation, WorldId = Id, Scenes = Scenes.Select(s => s.LuzScene).ToArray(), RevisionNumber = Revision }; var zoneFile = Path.Combine(path, Name); var root = Path.GetDirectoryName(zoneFile); if (!Directory.Exists(root)) { Directory.CreateDirectory(root); } await using var stream = File.Create(zoneFile); using var writer = new BitWriter(stream); file.Serialize(writer); foreach (var scene in Scenes) { await scene.SaveAsync(Path.Combine(path, Path.GetDirectoryName(Name))); } await Terrain.SaveAsync(root); }
public static GameObject Import(string workingFile) { const float scale = 3.125f; using var stream = File.OpenRead(workingFile); using var reader = new BitReader(stream); var zone = new LuzFile(); zone.Deserialize(reader); return(null); var zoneInstance = new GameObject($"Zone {Path.GetFileName(workingFile)}"); var zoneDetails = zoneInstance.AddOrGetComponent <ZoneDetails>(); zoneDetails.ZoneName = Path.GetFileName(workingFile); zoneDetails.ZoneId = zone.WorldId; var spawnPoint = new GameObject("Zone Spawnpoint"); spawnPoint.transform.parent = zoneInstance.transform; spawnPoint.transform.position = new Vector3(zone.SpawnPoint.X, zone.SpawnPoint.Y, zone.SpawnPoint.Z); spawnPoint.transform.rotation = new Quaternion(zone.SpawnRotation.X, zone.SpawnRotation.Y, zone.SpawnRotation.Z, zone.SpawnRotation.W); zoneDetails.SpawnPoint = spawnPoint.transform; var sourceDir = Path.GetDirectoryName(workingFile) ?? WorkspaceControl.CurrentWorkspace.AssetPath; var terrain = TerrainInterface.Import(Path.Combine( sourceDir, zone.TerrainFileName) ); terrain.transform.parent = zoneInstance.transform; foreach (var sceneInfo in zone.Scenes) { var scenePath = Path.Combine(sourceDir, sceneInfo.FileName); var sceneInstance = new GameObject($"Scene {sceneInfo.SceneName} ({sceneInfo.SceneId}, {sceneInfo.LayerId})"); var sceneDetails = sceneInstance.AddOrGetComponent <SceneDetails>(); sceneInstance.transform.parent = zoneInstance.transform; using var lvlStream = File.OpenRead(scenePath); using var lvlReader = new BitReader(lvlStream); var lvl = new LvlFile(); lvl.Deserialize(lvlReader); sceneDetails.SceneName = sceneInfo.SceneName; sceneDetails.SceneLayer = sceneInfo.LayerId; sceneDetails.SkyBox = lvl.LevelSkyConfig == null ? sceneDetails.SkyBox : lvl.LevelSkyConfig.Skybox; if (lvl.LevelObjects == null) { continue; } foreach (var template in lvl.LevelObjects.Templates) { GameObject lwoObject; try { lwoObject = ObjectInterface.Import(template.Lot, out var error); if (lwoObject == null) { Debug.LogError(error); continue; } } catch (Exception e) { Debug.LogError(e); continue; } lwoObject.transform.parent = sceneInstance.transform; lwoObject.transform.position = new Vector3(template.Position.X, template.Position.Y, template.Position.Z); lwoObject.transform.rotation = new Quaternion(template.Rotation.X, template.Rotation.Y, template.Rotation.Z, template.Rotation.W); } } return(zoneInstance); }
public async Task LoadZoneDataAsync(int seek) { Zones.Clear(); Logger.Information("Parsing zone info..."); var zone = await ClientCache.FindAsync <ZoneTable>(seek); if (zone == default) { Logger.Error($"Cannot find zone {seek}"); return; } ; var luzFile = Path.Combine("maps", zone.ZoneName.ToLower()); if (!luzFile.EndsWith(".luz")) { return; } Logger.Information($"Parsing: {luzFile}"); try { var luz = new LuzFile(); await using var stream = _resources.GetStream(luzFile); var reader = new BitReader(stream); luz.Deserialize(reader); var path = Path.GetDirectoryName(luzFile); var lvlFiles = new List <LvlFile>(); foreach (var scene in luz.Scenes) { await using var sceneStream = _resources.GetStream(Path.Combine(path, scene.FileName)); using var sceneReader = new BitReader(sceneStream); Logger.Information($"Parsing: {scene.FileName}"); var lvl = new LvlFile(); lvl.Deserialize(sceneReader); lvlFiles.Add(lvl); if (lvl.LevelObjects?.Templates == default) { continue; } foreach (var template in lvl.LevelObjects.Templates) { template.ObjectId |= 70368744177664; } } var terrainStream = _resources.GetStream(Path.Combine(path, luz.TerrainFileName)); using var terrainReader = new BitReader(terrainStream); var terrain = new TerrainFile(); terrain.Deserialize(terrainReader); var triggers = await TriggerDictionary.FromDirectoryAsync(Path.Combine(_resources.RootPath, path)); Logger.Information($"Parsed: {seek}"); Zones[seek] = new ZoneInfo { LuzFile = luz, LvlFiles = lvlFiles, TriggerDictionary = triggers, TerrainFile = terrain }; } catch (Exception e) { Logger.Error($"Failed to parse {luzFile}: {e.Message}\n{e.StackTrace}"); } }
public static async Task ExportToWavefrontAsync(this LuzFile @this, AccessDatabase database, string source, string resources, string result) { TerrainFile terrain; await using (var stream = File.OpenRead(Path.Combine(source, @this.TerrainFileName))) { using var reader = new BitReader(stream); terrain = new TerrainFile(); terrain.Deserialize(reader); } var levels = new LvlFile[@this.Scenes.Length]; for (var i = 0; i < @this.Scenes.Length; i++) { var scene = @this.Scenes[i]; await using var stream = File.OpenRead(Path.Combine(source, scene.FileName)); using var reader = new BitReader(stream); var level = new LvlFile(); level.Deserialize(reader); levels[i] = level; } var objects = new List <LevelObjectTemplate>(); foreach (var level in levels) { if (level.LevelObjects?.Templates == default) { continue; } foreach (var template in level.LevelObjects.Templates) { if (!template.LegoInfo.TryGetValue("add_to_navmesh", out var add)) { continue; } if (!(bool)add) { continue; } objects.Add(template); } } foreach (var template in objects) { var instance = database.LoadObject(template.Lot); var renderer = instance.GetComponent <RenderComponentTable>(); if (renderer == default) { continue; } Console.WriteLine(renderer.render_asset); } }
public static async Task InsertAsync(string path) { LuzFile luz; await using (var stream = File.OpenRead(path)) { using var reader = new BitReader(stream); luz = new LuzFile(); luz.Deserialize(reader); } var worlds = Interface.Database["ZoneTable"]; if (luz.WorldId == 0) { var attributes = File.GetAttributes(path); attributes &= ~FileAttributes.ReadOnly; File.SetAttributes(path, attributes); luz.WorldId = (uint)worlds.ClaimKey(100); await using var stream = File.Create(path); using var writer = new BitWriter(stream); luz.Serialize(writer); } var entry = worlds.FirstOrDefault(w => w.Key == luz.WorldId); if (entry != default) { if (entry.Value <string>("zoneName").StartsWith("ZoneTable")) { worlds.Remove(entry); } else { return; } } var rootPath = Path.GetDirectoryName(path); var terrain = await TerrainEditor.OpenAsync(Path.Combine(rootPath, luz.TerrainFileName)); entry = worlds.Create(luz.WorldId); var root = new Uri(Path.Combine(Interface.Configuration.Output, "./maps/")); var map = new Uri(path); var relative = root.MakeRelativeUri(map).ToString(); Console.WriteLine($"Inserting: [{luz.WorldId}] {Path.GetFileName(path)} into {relative}"); var _ = new ZoneTableTable(entry) { zoneName = relative, ghostdistance = 5000, zoneID = (int)luz.WorldId, scriptID = -1, ghostdistance_min = 150, heightInChunks = terrain.Source.Height, widthInChunks = terrain.Source.Weight, localize = false, petsAllowed = true, mountsAllowed = true }; }
public async Task LoadZoneDataAsync(int seek) { Zones.Clear(); var luzFiles = _resources.GetAllFilesWithExtension("luz"); foreach (var luzFile in luzFiles) { Logger.Information($"Parsing: {luzFile}"); try { var luz = new LuzFile(); await using var stream = _resources.GetStream(luzFile); var reader = new BitReader(stream); luz.Deserialize(reader); if (luz.WorldId != seek) { continue; } var path = Path.GetDirectoryName(luzFile); var triggers = await GetTriggers(path); var lvlFiles = new List <LvlFile>(); foreach (var scene in luz.Scenes) { await using var sceneStream = _resources.GetStream(Path.Combine(path, scene.FileName)); var sceneReader = new BitReader(sceneStream); var lvl = new LvlFile(); lvl.Deserialize(sceneReader); lvlFiles.Add(lvl); if (lvl.LevelObjects?.Templates == default) { continue; } foreach (var template in lvl.LevelObjects.Templates) { template.ObjectId |= 70368744177664; } } Logger.Information($"Parsed: {(ZoneId) luz.WorldId}"); Zones[(ZoneId)luz.WorldId] = new ZoneInfo { LuzFile = luz, LvlFiles = lvlFiles, Triggers = triggers.ToList() }; } catch (Exception e) { Logger.Error($"Failed to parse {luzFile}: {e.Message}\n{e.StackTrace}"); } } }
public override void OnImportAsset(AssetImportContext ctx) { _luzFile = new LuzFile($"{UniverseImporter.LuzImportDir}/{Path.GetFileName(ctx.assetPath)}"); var luzAssetPath = $"{Path.GetDirectoryName(ctx.assetPath)}/{Path.GetFileNameWithoutExtension(ctx.assetPath)}"; Directory.CreateDirectory(luzAssetPath); var objects = UniverseImporter.Database.Tables.First(s => s.Name.ToLower() == "componentsregistry"); var renderComps = UniverseImporter.Database.Tables.First(s => s.Name.ToLower() == "rendercomponent"); var spawnPoint = new GameObject("Spawn Point"); spawnPoint.transform.position = _luzFile.SpawnPoint; spawnPoint.transform.rotation = _luzFile.SpawnRotation; ctx.AddObjectToAsset("Spawn Point", spawnPoint); foreach (var lvlFile in _luzFile.LvlFiles) { foreach (var template in lvlFile.Chunks2001.SelectMany(c => c.Objects)) { if (template.Ldf.TryGetValue("spawntemplate", out var realId)) { Debug.Log($"{template.Lot} is spawner"); template.Lot = (int)realId; Debug.Log($"{template.Lot} came from spawner."); } /* * else if (template.Ldf.TryGetValue("loadSrvrOnly", out var serverOnly) && (bool) serverOnly || * template.Ldf.TryGetValue("carver_only", out var carverOnly) && (bool) carverOnly || * template.Ldf.TryGetValue("renderDisabled", out var disabled) && (bool) disabled) * { * continue; * } */ var comps = objects.Rows?.Where(r => r?.Fields[0]?.Value.ToString() == template.Lot.ToString()).ToArray(); var render = comps?.FirstOrDefault(r => r.Fields[1].Value.ToString() == "2"); if (render == null) { continue; } var renderId = render.Fields[2].Value.ToString(); var row = renderComps.Rows.First(s => s.Fields[0].Value.ToString() == renderId); var final = $"{Path.Combine(UniverseImporter.ResDir, row.Fields[1].Value.ToString())}"; final = final.Replace(@"\\", "/").Replace("\\", "/"); Debug.Log(final); try { var nifPath = $"{luzAssetPath}/{Path.GetFileName(final)}"; if (!File.Exists(nifPath)) { File.Copy(final, nifPath); AssetDatabase.ImportAsset(nifPath); } var obj = (GameObject)PrefabUtility.InstantiatePrefab( AssetDatabase.LoadAssetAtPath(nifPath, typeof(GameObject))); obj.transform.localPosition = template.Position; obj.transform.localRotation = template.Rotation; obj.transform.localScale = Vector3.one * template.Scale; } catch (Exception e) { Console.WriteLine(e); } Debug.Log(final); } } }
public static async Task UpgradeZone(string path) { var origin = path; var id = Interface.Database["ZoneTable"].ClaimKey(100); path = Path.Combine(Interface.Configuration.Output, "maps", path); LuzFile luz; var root = Path.GetDirectoryName(path); await using (var stream = File.OpenRead(path)) { using var reader = new BitReader(stream); luz = new LuzFile(); luz.Deserialize(reader); } foreach (var scene in luz.Scenes) { LvlFile lvl; var scenePath = Path.Combine(root, scene.FileName); await using (var stream = File.OpenRead(scenePath)) { using var reader = new BitReader(stream); lvl = new LvlFile(); lvl.Deserialize(reader); } if (lvl.IsOld) { Console.WriteLine($"Converting {scene.SceneName} to new."); lvl.ConvertToNew(); await using (var stream = File.Create(scenePath)) { using var writer = new BitWriter(stream); lvl.Serialize(writer); } } var spawnPoint = lvl.LevelObjects?.Templates?.FirstOrDefault(l => l.Lot == 4945); if (spawnPoint == null) { continue; } luz.SpawnPoint = spawnPoint.Position; luz.SpawnRotation = spawnPoint.Rotation; } if (luz.Version < 0x26) { Console.WriteLine($"Converting {Path.GetFileName(path)} to new."); luz.Version = 0x26; luz.WorldId = (uint)id; await using (var stream = File.Create(path)) { using var writer = new BitWriter(stream); luz.Serialize(writer); } } Console.WriteLine("Updating terrain."); var terrainPath = Path.Combine(root, luz.TerrainFileName); var terrain = await TerrainEditor.OpenAsync(terrainPath); foreach (var chunk in terrain.Source.Chunks) { for (var i = 0; i < chunk.ColorRelatedArray.Length; i++) { chunk.ColorRelatedArray[i] = 1; } } await terrain.SaveAsync(terrainPath); Console.WriteLine($"Adding [{id}] {Path.GetFileName(path)} to database."); var zones = Interface.Database["ZoneTable"]; var row = zones.Create(id); var _ = new ZoneTableTable(row) { zoneName = origin, zoneID = (int)luz.WorldId, ghostdistance = 500, scriptID = -1, locStatus = 0 }; }