Initial commit: OpenRA game engine
Fork from OpenRA/OpenRA with one-click launch script (start-ra.cmd) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
109
OpenRA.Game/FileFormats/ReplayMetadata.cs
Normal file
109
OpenRA.Game/FileFormats/ReplayMetadata.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
public class ReplayMetadata
|
||||
{
|
||||
// Must be an invalid replay 'client' value
|
||||
public const int MetaStartMarker = -1;
|
||||
public const int MetaEndMarker = -2;
|
||||
public const int MetaVersion = 0x00000001;
|
||||
|
||||
public readonly GameInformation GameInfo;
|
||||
public string FilePath { get; private set; }
|
||||
|
||||
public ReplayMetadata(GameInformation info)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(info);
|
||||
|
||||
GameInfo = info;
|
||||
}
|
||||
|
||||
ReplayMetadata(FileStream fs, string path)
|
||||
{
|
||||
FilePath = path;
|
||||
|
||||
// Read start marker
|
||||
if (fs.ReadInt32() != MetaStartMarker)
|
||||
throw new InvalidOperationException("Expected MetaStartMarker but found an invalid value.");
|
||||
|
||||
// Read version
|
||||
var version = fs.ReadInt32();
|
||||
if (version != MetaVersion)
|
||||
throw new NotSupportedException($"Metadata version {version} is not supported");
|
||||
|
||||
// Read game info (max 100K limit as a safeguard against corrupted files)
|
||||
var data = fs.ReadLengthPrefixedString(Encoding.UTF8, 1024 * 100);
|
||||
GameInfo = GameInformation.Deserialize(data, path);
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter writer)
|
||||
{
|
||||
// Write start marker & version
|
||||
writer.Write(MetaStartMarker);
|
||||
writer.Write(MetaVersion);
|
||||
|
||||
// Write data
|
||||
var dataLength = 0;
|
||||
{
|
||||
// Write lobby info data
|
||||
writer.Flush();
|
||||
dataLength += writer.BaseStream.WriteLengthPrefixedString(Encoding.UTF8, GameInfo.Serialize());
|
||||
}
|
||||
|
||||
// Write total length & end marker
|
||||
writer.Write(dataLength);
|
||||
writer.Write(MetaEndMarker);
|
||||
}
|
||||
|
||||
public void RenameFile(string newFilenameWithoutExtension)
|
||||
{
|
||||
var newPath = Path.Combine(Path.GetDirectoryName(FilePath), newFilenameWithoutExtension) + ".orarep";
|
||||
File.Move(FilePath, newPath);
|
||||
FilePath = newPath;
|
||||
}
|
||||
|
||||
public static ReplayMetadata Read(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var fs = new FileStream(path, FileMode.Open))
|
||||
{
|
||||
if (!fs.CanSeek)
|
||||
return null;
|
||||
|
||||
if (fs.Length < 20)
|
||||
return null;
|
||||
|
||||
fs.Seek(-(4 + 4), SeekOrigin.End);
|
||||
var dataLength = fs.ReadInt32();
|
||||
if (fs.ReadInt32() == MetaEndMarker)
|
||||
{
|
||||
// Go back by (end marker + length storage + data + version + start marker) bytes
|
||||
fs.Seek(-(4 + 4 + dataLength + 4 + 4), SeekOrigin.Current);
|
||||
return new ReplayMetadata(fs, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Write("debug", ex.ToString());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user