コード例 #1
0
        /// <summary>
        /// Gets the byte representation of the command
        /// </summary>
        /// <param name="settings">The game settings</param>
        /// <returns>The command bytes</returns>
        public byte[] ToBytes(GameSettings settings)
        {
            using (var context = new Context(settings)) {
                // Create a memory stream
                using (var memStream = new MemoryStream()) {
                    // Stream key
                    const string key = "PC_EventCommand";

                    // Add the stream
                    context.AddStreamFile(key, memStream);

                    // TODO: Pass in this instance
                    // Serialize the command
                    FileFactory.Write <R1_EventCommandCollection>(key, this, context);

                    // Return the bytes
                    return(memStream.ToArray());
                }
            }
        }
コード例 #2
0
ファイル: R1_PS1_Manager.cs プロジェクト: PluMGMK/Ray1Map
        protected void CreateISO(Context context)
        {
            // Get the xml file
            const string xmlFilePath = "disc.xml";

            // Close the context so the files can be accessed by other processes
            context.Close();

            // Create a temporary file for the LBA log
            using (var lbaLogFile = new TempFile())
            {
                // Recalculate the LBA for the files on the disc
                ProcessHelpers.RunProcess(Settings.Tool_mkpsxiso_filePath, new string[]
                {
                    "-lba", ProcessHelpers.GetStringAsPathArg(lbaLogFile.TempPath), // Specify LBA log path
                    "-noisogen",                                                    // Don't generate an ISO now
                    xmlFilePath                                                     // The xml path
                }, workingDir: context.BasePath);

                // Read the LBA log
                using (var lbaLogStream = lbaLogFile.OpenRead())
                {
                    using (var reader = new StreamReader(lbaLogStream))
                    {
                        // Skip initial lines
                        for (int i = 0; i < 8; i++)
                        {
                            reader.ReadLine();
                        }

                        var logEntries  = new List <LBALogEntry>();
                        var currentDirs = new List <string>();

                        // Read all log entries
                        while (!reader.EndOfStream)
                        {
                            var line = reader.ReadLine();

                            if (line == null)
                            {
                                break;
                            }

                            var words = line.Split(' ').Where(x => !String.IsNullOrWhiteSpace(x)).ToArray();

                            if (!words.Any())
                            {
                                continue;
                            }

                            var entry = new LBALogEntry(words, currentDirs);

                            logEntries.Add(entry);

                            if (entry.EntryType == LBALogEntry.Type.Dir)
                            {
                                currentDirs.Add(entry.Name);
                            }

                            if (entry.EntryType == LBALogEntry.Type.End)
                            {
                                currentDirs.RemoveAt(currentDirs.Count - 1);
                            }
                        }

                        // Read the game exe
                        var exe = FileFactory.Read <R1_PS1_Executable>(ExeFilePath, context);

                        // Update every file path in the file table
                        foreach (var fileEntry in exe.FileTable)
                        {
                            // Get the matching entry
                            var entry = logEntries.FirstOrDefault(x => x.FullPath == fileEntry.FilePath);

                            if (entry == null)
                            {
                                if (!String.IsNullOrWhiteSpace(fileEntry.FilePath))
                                {
                                    Debug.Log($"LBA not updated for {fileEntry.FilePath}");
                                }

                                continue;
                            }

                            // Update the LBA and size
                            fileEntry.LBA      = entry.LBA;
                            fileEntry.FileSize = (uint)entry.Bytes;
                        }

                        // Write the game exe
                        FileFactory.Write <R1_PS1_Executable>(ExeFilePath, context);
                    }
                }
            }

            // Close context again so the exe can be accessed
            context.Close();

            // Create a new ISO
            ProcessHelpers.RunProcess(Settings.Tool_mkpsxiso_filePath, new string[]
            {
                "-y",       // Set to always overwrite
                xmlFilePath // The xml path
            }, workingDir: context.BasePath, logInfo: false);
        }
コード例 #3
0
ファイル: R1_PS1_Manager.cs プロジェクト: PluMGMK/Ray1Map
        /// <summary>
        /// Saves the specified level
        /// </summary>
        /// <param name="context">The serialization context</param>
        /// <param name="lvl">The level</param>
        public override UniTask SaveLevelAsync(Context context, Unity_Level lvl)
        {
            // Menu levels can't be saved
            if (context.Settings.R1_World == R1_World.Menu)
            {
                return(UniTask.CompletedTask);
            }

            // Get the level file path
            var lvlPath = GetLevelFilePath(context.Settings);

            // Get the level data
            var lvlData = context.GetMainFileObject <R1_PS1_LevFile>(lvlPath);

            // Get the object manager
            var objManager = (Unity_ObjectManager_R1)lvl.ObjManager;

            // Update the tiles
            for (int y = 0; y < lvlData.MapData.Height; y++)
            {
                for (int x = 0; x < lvlData.MapData.Width; x++)
                {
                    // Set the tile
                    lvlData.MapData.Tiles[y * lvlData.MapData.Width + x] = lvl.Maps[0].MapTiles[y * lvlData.MapData.Width + x].Data;
                }
            }

            var newEvents = lvl.EventData.Cast <Unity_Object_R1>().Select(e =>
            {
                var ed = e.EventData;

                if (ed.PS1Demo_Unk1 == null)
                {
                    ed.PS1Demo_Unk1 = new byte[40];
                }

                if (ed.Unk_98 == null)
                {
                    ed.Unk_98 = new byte[5];
                }

                // TODO: Do this in the Unity_Object instead
                ed.ImageDescriptorCount = (ushort)objManager.DES[e.DESIndex].Data.ImageDescriptors.Length;
                ed.AnimDescriptorCount  = (byte)objManager.DES[e.DESIndex].Data.Graphics.Animations.Count;

                // TODO: Get from DESData in obj manager instead?
                ed.ImageDescriptors = FileFactory.Read <ObjectArray <R1_ImageDescriptor> >(ed.ImageDescriptorsPointer, context, (s, o) => o.Length = ed.ImageDescriptorCount).Value;
                ed.AnimDescriptors  = FileFactory.Read <ObjectArray <R1_PS1_AnimationDescriptor> >(ed.AnimDescriptorsPointer, context, (s, o) => o.Length = ed.AnimDescriptorCount).Value;
                ed.ETA = context.Cache.FromOffset <R1_PS1_ETA>(ed.ETAPointer);

                // TODO: Update this
                //ed.ImageBuffer = des.ImageBuffer;

                return(ed);
            }).ToArray();

            var newEventLinkTable = objManager.LinkTable.Select(x => (byte)x).ToArray();

            // Relocate pointers to a new block of data we append to the level file
            UpdateAndFillDataBlock(lvlData.Offset + lvlData.FileSize, lvlData.EventData, newEvents, newEventLinkTable, context.Settings);

            // TODO: When writing make sure that ONLY the level file gets recreated - do not touch the other files (ignore DoAt if the file needs to be switched based on some setting?)
            // Save the file
            FileFactory.Write <R1_PS1_LevFile>(lvlPath, context);

            // Create ISO for the modified data
            CreateISO(context);

            return(UniTask.CompletedTask);
        }
コード例 #4
0
ファイル: R1_Kit_Manager.cs プロジェクト: PluMGMK/Ray1Map
        public async UniTask ImportDESETA(GameSettings settings, bool edu)
        {
            // TODO: Not hard-code these?
            const int desAllfixCount      = 9;
            const int etaAllfixCount      = 5;
            int       otherDesAllfixCount = edu ? 8 : 7;
            int       otherEtaAllfixCount = edu ? 5 : 4;

            // Load in the JSON files to get our mappings
            await LevelEditorData.InitAsync(settings, true);

            using (var context = new Context(settings))
            {
                GameSettings otherSettings;

                if (!edu)
                {
                    // Find the first Rayman 1 version that the user has actually set up.
                    var mode = EnumHelpers.GetValues <GameModeSelection>().Where(x => x.GetAttribute <GameModeAttribute>().EngineVersion == EngineVersion.R1_PC).First(x => Settings.GameDirectories.ContainsKey(x) && Directory.Exists(Settings.GameDirectories[x]));

                    otherSettings = new GameSettings(mode, Settings.GameDirectories[mode], settings.World, settings.Level);
                }
                else
                {
                    otherSettings = new GameSettings(GameModeSelection.RaymanEducationalPC, Settings.GameDirectories[GameModeSelection.RaymanEducationalPC], settings.World, settings.Level);
                }

                using (var otherContext = new Context(otherSettings)) {
                    // Create manager for the other game, and load its files.
                    R1_PCBaseManager otherGame = (R1_PCBaseManager)otherSettings.GetGameManager;

                    if (edu)
                    {
                        otherContext.Settings.EduVolume = otherGame.GetLevels(otherContext.Settings).First().Name;
                    }

                    // Loop through the worlds.
                    for (int w = 1; w < 7; w++)
                    {
                        context.Settings.World = otherContext.Settings.World = w;
                        var wldPath = GetWorldFilePath(context.Settings);

                        await LoadFilesAsync(context);

                        await otherGame.LoadFilesAsync(otherContext);

                        // Load our WLD file and the other game's.
                        var wld      = FileFactory.Read <R1_PC_WorldFile>(wldPath, context);
                        var otherWld = FileFactory.Read <R1_PC_WorldFile>(otherGame.GetWorldFilePath(otherContext.Settings), otherContext);

                        // Get the list of existing ETA and DES files so we know what's missing.
                        var desNames = wld.DESFileNames.ToArray();
                        var etaNames = wld.ETAFileNames.ToArray();

                        // Use the tables to get mappings from the other game onto this one.
                        var desMappings = new Dictionary <int, string>();
                        var etaMappings = new Dictionary <int, string>();
                        var r1wld       = otherContext.Settings.R1_World;

                        var desNameTable = otherGame.GetDESNameTable(otherContext);
                        var etaNameTable = otherGame.GetETANameTable(otherContext);

                        // Go through the other game's DES and ETA name tables, and see if any one
                        // is missing from Designer.
                        for (int iDes = 0; iDes < desNameTable.Length; iDes++)
                        {
                            var desName = desNameTable[iDes];
                            if ((desName == null) || (desName == "N/A"))
                            {
                                continue;
                            }
                            if (!desNames.Contains($"{desName}.DES"))
                            {
                                // The DES is specified in the JSON file, but doesn't exist in the WLD file.
                                // Add it to the copy list.
                                desMappings[iDes] = $"{desName}.DES";

                                Debug.Log($"Mapping DES {iDes} to {desName}");
                            }
                        }
                        for (int iEta = 0; iEta < etaNameTable.Length; iEta++)
                        {
                            var etaName = etaNameTable[iEta];
                            if ((etaName == null) || (etaName == "N/A"))
                            {
                                continue;
                            }
                            if (!etaNames.Contains($"{etaName}.ETA"))
                            {
                                // The ETA is specified in the JSON file, but doesn't exist in the WLD file.
                                // Add it to the copy list.
                                etaMappings[iEta] = $"{etaName}.ETA";

                                Debug.Log($"Mapping ETA {iEta} to {etaName}");
                            }
                        }

                        // Now that we've set up the mappings, carry out the copies!
                        var newDesItems = wld.DesItems.ToList();
                        foreach (var mapping in desMappings)
                        {
                            Debug.Log($"Attempting to port DES {mapping.Key} -> {mapping.Value}");
                            newDesItems.Add(otherWld.DesItems[mapping.Key - otherDesAllfixCount - 1]);
                            wld.DesItemCount = (ushort)newDesItems.Count;
                            wld.DESFileNames[wld.DesItemCount + desAllfixCount - 1] = mapping.Value;
                        }
                        wld.DesItems = newDesItems.ToArray();

                        var newEtaItems = wld.Eta.ToList();
                        foreach (var mapping in etaMappings)
                        {
                            Debug.Log($"Attempting to port ETA {mapping.Key} -> {mapping.Value}");
                            newEtaItems.Add(otherWld.Eta[mapping.Key - otherEtaAllfixCount]);
                            wld.ETAFileNames[newEtaItems.Count + etaAllfixCount - 1] = mapping.Value;
                        }
                        wld.Eta = newEtaItems.ToArray();

                        // Save the WLD
                        FileFactory.Write <R1_PC_WorldFile>(wldPath, context);
                    }
                }
            }

            // Beef up the memory allocation if necessary.
            await IncreaseMemAlloc(settings);
        }
コード例 #5
0
ファイル: MapConverter.cs プロジェクト: rtsonneveld/Ray1Map
        public static async UniTask MapperToRDAsync(GameSettings inputSettings, GameSettings outputSettings)
        {
            using (var inputContext = new Context(inputSettings))
            {
                using (var outputContext = new Context(outputSettings))
                {
                    // Create managers
                    var mapperManager = new R1_Mapper_Manager();
                    var rdManager     = new R1_Kit_Manager();

                    // Load files to context
                    await mapperManager.LoadFilesAsync(inputContext);

                    await rdManager.LoadFilesAsync(outputContext);

                    // Load the mapper level
                    var inputLev        = (await mapperManager.LoadAsync(inputContext, false));
                    var inputMap        = inputLev.Maps[0];
                    var inputObjManager = (Unity_ObjectManager_R1)inputLev.ObjManager;

                    // Load the editor manager data for the output level
                    var outData = await rdManager.LoadAsync(outputContext, true);

                    var outputObjManager = (Unity_ObjectManager_R1)outData.ObjManager;

                    // Load a dummy PC level as a base
                    var outLev = FileFactory.Read <R1_PC_LevFile>(rdManager.GetLevelFilePath(outputSettings), outputContext);

                    // TODO: Set background data

                    // Set map data
                    outLev.MapData.Width  = inputMap.Width;
                    outLev.MapData.Height = inputMap.Height;
                    //outLev.MapData.ColorPalettes = new RGB666Color[][]
                    //{
                    //    FileFactory.Read<PCX>(mapperManager.GetPCXFilePath(inputSettings), inputContext).VGAPalette.Select(x => new RGB666Color(x.Red, x.Green, x.Blue)).ToArray()
                    //};

                    // Set tiles while keeping track of the size changes
                    var prevTileSize = outLev.MapData.Tiles.Length * 6;
                    outLev.MapData.Tiles = inputMap.MapTiles.Select(x => x.Data).ToArray();
                    var newTileSize = outLev.MapData.Tiles.Length * 6;

                    // Update pointers
                    outLev.EventBlockPointer   += newTileSize - prevTileSize;
                    outLev.TextureBlockPointer += newTileSize - prevTileSize;

                    // TODO: Set tilemap from .pcx file
                    //outLev.TileTextureData = null;

                    // Get the file tables
                    var outputDesNames = FileFactory.Read <R1_PC_WorldFile>(rdManager.GetWorldFilePath(outputSettings), outputContext).DESFileNames;
                    var outputEtaNames = FileFactory.Read <R1_PC_WorldFile>(rdManager.GetWorldFilePath(outputSettings), outputContext).ETAFileNames;

                    // Set event data
                    outLev.EventData.EventCount        = (ushort)inputLev.EventData.Count;
                    outLev.EventData.EventLinkingTable = inputObjManager.LinkTable;
                    outLev.EventData.Events            = inputLev.EventData.Cast <Unity_Object_R1>().Select(x =>
                    {
                        var e = x.EventData;

                        var newDesIndex = (uint)outputDesNames.FindItemIndex(y => y == inputObjManager.DES[x.DESIndex].Name);
                        var newEtaIndex = (uint)outputEtaNames.FindItemIndex(y => y == inputObjManager.ETA[x.ETAIndex].Name);

                        // Set DES and ETA indexes
                        e.PC_ImageDescriptorsIndex     = newDesIndex;
                        e.PC_ImageBufferIndex          = newDesIndex;
                        e.PC_AnimationDescriptorsIndex = newDesIndex;
                        e.PC_ETAIndex = newEtaIndex;

                        // Set image and animation descriptor counts
                        e.ImageDescriptorCount = (ushort)outputObjManager.DES[x.DESIndex].Data.Graphics.Sprites.Count;
                        e.AnimDescriptorCount  = (byte)outputObjManager.DES[x.DESIndex].Data.Graphics.Animations.Count;

                        return(e);
                    }).ToArray();

                    // Set event commands
                    outLev.EventData.EventCommands = inputLev.EventData.Cast <Unity_Object_R1>().Select(x =>
                    {
                        // Get the commands in the compiled format
                        var cmds = EventCommandCompiler.Compile(x.EventData.Commands, x.EventData.Commands.ToBytes(inputSettings));

                        // Remove commands which only contain the invalid command
                        if (cmds.Commands.Commands.Length == 1)
                        {
                            cmds = new EventCommandCompiler.CompiledEventCommandData(new R1_EventCommandCollection()
                            {
                                Commands = new R1_EventCommand[0]
                            }, new ushort[0]);
                        }

                        // Create a command object
                        return(new R1_PC_EventCommand
                        {
                            CommandLength = (ushort)cmds.Commands.Commands.Select(y => y.Length).Sum(),
                            Commands = cmds.Commands,
                            LabelOffsetCount = (ushort)cmds.LabelOffsets.Length,
                            LabelOffsetTable = cmds.LabelOffsets
                        });
                    }).ToArray();

                    // TODO: Get data from .ini file
                    // Set profile define data
                    outLev.ProfileDefine = new R1_PC_ProfileDefine
                    {
                        LevelName         = "Test Export",
                        LevelAuthor       = "RayCarrot",
                        LevelDescription  = "This is a test export map",
                        Power_Fist        = true,
                        Power_Hang        = true,
                        Power_Run         = true,
                        Power_Seed        = false,
                        Power_Helico      = true,
                        Power_SuperHelico = false
                    };

                    // Write the changes to the file
                    FileFactory.Write <R1_PC_LevFile>(rdManager.GetLevelFilePath(outputSettings), outputContext);
                }
            }
        }
コード例 #6
0
        public async UniTask ExportMusicAsync(GameSettings settings, string outputPath)
        {
            using (var context = new Context(settings)) {
                var s = context.Deserializer;

                void ExportSampleSigned(string directory, string filename, sbyte[] data, uint sampleRate, ushort channels)
                {
                    // Create the directory
                    Directory.CreateDirectory(directory);

                    byte[] unsignedData = data.Select(b => (byte)(b + 128)).ToArray();

                    // Create WAV data
                    var formatChunk = new WAVFormatChunk()
                    {
                        ChunkHeader   = "fmt ",
                        FormatType    = 1,
                        ChannelCount  = channels,
                        SampleRate    = sampleRate,
                        BitsPerSample = 8,
                    };

                    var wav = new WAV {
                        Magic          = "RIFF",
                        FileTypeHeader = "WAVE",
                        Chunks         = new WAVChunk[]
                        {
                            formatChunk,
                            new WAVChunk()
                            {
                                ChunkHeader = "data",
                                Data        = unsignedData
                            }
                        }
                    };

                    formatChunk.ByteRate   = (formatChunk.SampleRate * formatChunk.BitsPerSample * formatChunk.ChannelCount) / 8;
                    formatChunk.BlockAlign = (ushort)((formatChunk.BitsPerSample * formatChunk.ChannelCount) / 8);

                    // Get the output path
                    var outputFilePath = Path.Combine(directory, filename + ".wav");

                    // Create and open the output file
                    using (var outputStream = File.Create(outputFilePath)) {
                        // Create a context
                        using (var wavContext = new Context(settings)) {
                            // Create a key
                            const string wavKey = "wav";

                            // Add the file to the context
                            wavContext.AddFile(new StreamFile(wavKey, outputStream, wavContext));

                            // Write the data
                            FileFactory.Write <WAV>(wavKey, wav, wavContext);
                        }
                    }
                }

                await LoadFilesAsync(context);

                Pointer    ptr          = context.FilePointer(GetROMFilePath);
                var        pointerTable = PointerTables.GBAIsometric_PointerTable(s.GameSettings.GameModeSelection, ptr.file);
                MusyX_File musyxFile    = null;
                s.DoAt(pointerTable[GBAIsometric_Pointer.MusyxFile], () => {
                    musyxFile = s.SerializeObject <MusyX_File>(musyxFile, name: nameof(musyxFile));
                });
                string outPath = outputPath + "/Sounds/";
                for (int i = 0; i < musyxFile.SampleTable.Value.Samples.Length; i++)
                {
                    var e = musyxFile.SampleTable.Value.Samples[i].Value;
                    //Util.ByteArrayToFile(outPath + $"{i}_{e.Offset.AbsoluteOffset:X8}.bin", e.SampleData);
                    ExportSampleSigned(outPath, $"{i}_{musyxFile.SampleTable.Value.Samples[i].pointer.SerializedOffset:X8}", e.SampleData, e.SampleRate, 1);
                }
                outPath = outputPath + "/SongData/";
                for (int i = 0; i < musyxFile.SongTable.Value.Length; i++)
                {
                    var songBytes = musyxFile.SongTable.Value.SongBytes[i];
                    Util.ByteArrayToFile(outPath + $"{i}_{musyxFile.SongTable.Value.Songs[i].SerializedOffset:X8}.son", songBytes);
                }
                outPath = outputPath + "/InstrumentData/";
                for (int i = 0; i < musyxFile.InstrumentTable.Value.Instruments.Length; i++)
                {
                    var instrumentBytes = musyxFile.InstrumentTable.Value.InstrumentBytes[i];
                    Util.ByteArrayToFile(outPath + $"{i}_{musyxFile.InstrumentTable.Value.Instruments[i].SerializedOffset:X8}.bin", instrumentBytes);
                }
            }
        }