public override Unity_Object CreateObject(int index) { // Get the event var e = AvailableEvents[index]; // Get the commands and label offsets R1_EventCommandCollection cmds = null; ushort[] labelOffsets = null; // If local (non-compiled) commands are used, attempt to get them from the event info or decompile the compiled ones if (UsesLocalCommands) { cmds = EventCommandCompiler.Decompile(new EventCommandCompiler.CompiledEventCommandData(R1_EventCommandCollection.FromBytes(e.Commands, Context.Settings), e.LabelOffsets), e.Commands); } else if (e.Commands.Any()) { cmds = R1_EventCommandCollection.FromBytes(e.Commands, Context.Settings); labelOffsets = e.LabelOffsets.Any() ? e.LabelOffsets : null; } var eventData = new Unity_Object_R1(new R1_EventData() { Type = (R1_EventType)e.Type, Etat = e.Etat, SubEtat = e.SubEtat, OffsetBX = e.OffsetBX, OffsetBY = e.OffsetBY, OffsetHY = e.OffsetHY, FollowSprite = e.FollowSprite, DisplayPrio = 0, HitSprite = e.HitSprite, Commands = cmds, LabelOffsets = labelOffsets }, this, ETAIndex: ETA.FindItemIndex(x => x.Name == e.ETA)); eventData.EventData.SetFollowEnabled(Context.Settings, e.FollowEnabled); // We need to set the hit points after the type eventData.EventData.ActualHitPoints = e.HitPoints; // Set DES eventData.DESIndex = DES.FindItemIndex(x => x.Name == e.DES); return(eventData); }
/// <summary> /// Loads the specified level for the editor /// </summary> /// <param name="context">The serialization context</param> /// <param name="loadTextures">Indicates if textures should be loaded</param> /// <returns>The level</returns> public override async UniTask <Unity_Level> LoadAsync(Context context, bool loadTextures) { // Get the level folder path var basePath = await GetLevelFolderPath(context); // TODO: Parse .ini file to get background etc. // Get file paths var mapPath = GetMapFilePath(basePath); var mapEventsPath = GetMapEventsFilePath(basePath); var saveEventsPath = GetSaveEventsFilePath(basePath); var pcxPath = GetPCXFilePath(context.Settings); var eventsCsvPath = GetEventManfiestFilePath(context.Settings.R1_World); // Load files to context await AddFile(context, mapPath); await AddFile(context, mapEventsPath, endianness : BinaryFile.Endian.Big); // Big endian just like on Jaguar await AddFile(context, pcxPath); // Read the files Controller.DetailedState = $"Loading map data"; await Controller.WaitIfNecessary(); var mapData = FileFactory.Read <MapData>(mapPath, context); Controller.DetailedState = $"Loading event data"; await Controller.WaitIfNecessary(); var mapEvents = FileFactory.Read <R1Jaguar_MapEvents>(mapEventsPath, context); var saveEvents = FileFactory.ReadText <R1_Mapper_SaveEvents>(saveEventsPath, context); var csv = FileFactory.ReadText <R1_Mapper_EventManifest>(eventsCsvPath, context); Controller.DetailedState = $"Loading tileset"; await Controller.WaitIfNecessary(); var pcx = FileFactory.Read <PCX>(pcxPath, context); // Get the palette from the PCX file var vgaPalette = pcx.VGAPalette; // Load the sprites var eventDesigns = loadTextures ? await LoadSpritesAsync(context, vgaPalette) : new Unity_ObjectManager_R1.DESData[0]; // Read the world data var worldData = FileFactory.Read <R1_PC_WorldFile>(GetWorldFilePath(context.Settings), context); var maps = new Unity_Map[] { new Unity_Map() { // Set the dimensions Width = mapData.Width, Height = mapData.Height, // Create the tile arrays TileSet = new Unity_MapTileMap[1], MapTiles = mapData.Tiles.Select(x => new Unity_Tile(x)).ToArray(), TileSetWidth = 1 } }; var allEventInstances = saveEvents.SaveEventInstances.SelectMany(x => x).ToArray(); // Create a linking table var linkTable = new ushort[allEventInstances.Length]; // Handle each event link group foreach (var linkedEvents in allEventInstances.Select((x, i) => new { Index = i, Data = x }).GroupBy(x => x.Data.LinkID)) { // Get the group var group = linkedEvents.ToArray(); // Handle every event for (int i = 0; i < group.Length; i++) { // Get the item var item = group[i]; if (group.Length == i + 1) { linkTable[item.Index] = (ushort)group[0].Index; } else { linkTable[item.Index] = (ushort)group[i + 1].Index; } } } // Create the object manager var objManager = new Unity_ObjectManager_R1( context: context, des: eventDesigns.Select((x, i) => new Unity_ObjectManager_R1.DataContainer <Unity_ObjectManager_R1.DESData>(x, i, worldData.DESFileNames?.ElementAtOrDefault(i))).ToArray(), eta: GetCurrentEventStates(context).Select((x, i) => new Unity_ObjectManager_R1.DataContainer <R1_EventState[][]>(x.States, i, worldData.ETAFileNames?.ElementAtOrDefault(i))).ToArray(), linkTable: linkTable, usesPointers: false, hasDefinedDesEtaNames: true); Controller.DetailedState = $"Loading events"; await Controller.WaitIfNecessary(); var levelEvents = new List <Unity_Object>(); // Create events for (var i = 0; i < saveEvents.SaveEventInstances.Length; i++) { // Get the map base position, based on the event map var mapPos = mapEvents.EventIndexMap.FindItemIndex(z => z == i + 1); // Get the x and y positions var mapY = (uint)Math.Floor(mapPos / (double)(mapEvents.Width)); var mapX = (uint)(mapPos - (mapY * mapEvents.Width)); // Calculate the actual position on the map mapX *= 4 * (uint)Settings.CellSize; mapY *= 4 * (uint)Settings.CellSize; // Add every instance foreach (var instance in saveEvents.SaveEventInstances[i]) { // Get the definition var def = csv.EventDefinitions.FirstOrDefault(x => x.Name == instance.EventDefinitionKey); if (def == null) { throw new Exception($"No matching event definition found for {instance.EventDefinitionKey}"); } var ed = new R1_EventData() { Type = def.Type, Etat = def.Etat, SubEtat = def.SubEtat, XPosition = (short)(mapX + instance.OffsetX), YPosition = (short)(mapY + instance.OffsetY), OffsetBX = def.OffsetBX, OffsetBY = def.OffsetBY, OffsetHY = def.OffsetHY, FollowSprite = def.FollowSprite, ActualHitPoints = (uint)instance.HitPoints, DisplayPrio = instance.DisplayPrio, HitSprite = def.HitSprite, PS1Demo_Unk1 = new byte[40], Unk_98 = new byte[5], LabelOffsets = new ushort[0], Commands = R1_EventCommandCollection.FromBytes(def.EventCommands, context.Settings), }; ed.SetFollowEnabled(context.Settings, def.FollowEnabled > 0); // Add the event levelEvents.Add(new Unity_Object_R1( eventData: ed, objManager: objManager, ETAIndex: worldData.ETAFileNames.FindItemIndex(x => x == def.ETAFile)) { DESIndex = worldData.DESFileNames.FindItemIndex(x => x.Length > 4 && x.Substring(0, x.Length - 4) == def.DESFile) }); } } // Convert levelData to common level format var level = new Unity_Level(maps, objManager, levelEvents, rayman: new Unity_Object_R1(R1_EventData.GetRayman(context, levelEvents.Cast <Unity_Object_R1>().FirstOrDefault(x => x.EventData.Type == R1_EventType.TYPE_RAY_POS)?.EventData), objManager)); Controller.DetailedState = $"Creating tileset"; await Controller.WaitIfNecessary(); // Load the tile set level.Maps[0].TileSet[0] = LoadTileSet(pcx); // Return the level return(level); }