Files
OpenRA/OpenRA.Game/FileFormats/ReplayMetadata.cs
Pavlos Touboulidis de0a5ebd43 Improve replay metadata and the replay browser
List of changes:

* Better and more filters with new layout, for both mods.

* Rename/Delete/Detele all functionality.

* Simplified ReplayMetadata class considerably by introducing a new
GameInformation data object. The new GameInformation class contains
more information than previously available so the new solution is not
compatible with old replays, meaning it can't read old replays.

* Better and cleaner game information gathering in order to be written
at the end of the replay file.

* Revert changes to ReplayConnection, no longer necessary.

* Better exception message on missing sprites and fonts.

* New "SpawnOccupant" class that holds all the information needed by the
MapPreviewWidget to visualize a spawn point. It was using Session.Client
before and it was necessary to separate it to be able to show information
not available at lobby time.

* Fix keyboard focus UI bug when closing a window would not remove focus.
2014-05-22 21:54:14 +03:00

137 lines
3.2 KiB
C#

#region Copyright & License Information
/*
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* 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. For more information,
* see COPYING.
*/
#endregion
using System;
using System.IO;
using System.Text;
using OpenRA.Network;
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)
{
if (info == null)
throw new ArgumentNullException("info");
GameInfo = info;
}
ReplayMetadata(BinaryReader reader, string path)
{
FilePath = path;
// Read start marker
if (reader.ReadInt32() != MetaStartMarker)
throw new InvalidOperationException("Expected MetaStartMarker but found an invalid value.");
// Read version
var version = reader.ReadInt32();
if (version != MetaVersion)
throw new NotSupportedException("Metadata version {0} is not supported".F(version));
// Read game info
string data = ReadUtf8String(reader);
GameInfo = GameInformation.Deserialize(data);
}
public void Write(BinaryWriter writer)
{
// Write start marker & version
writer.Write(MetaStartMarker);
writer.Write(MetaVersion);
// Write data
int dataLength = 0;
{
// Write lobby info data
dataLength += WriteUtf8String(writer, 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) + ".rep";
File.Move(FilePath, newPath);
FilePath = newPath;
}
public static ReplayMetadata Read(string path)
{
using (var fs = new FileStream(path, FileMode.Open))
return Read(fs, path);
}
static ReplayMetadata Read(FileStream fs, string path)
{
if (!fs.CanSeek)
return null;
fs.Seek(-(4 + 4), SeekOrigin.End);
using (var reader = new BinaryReader(fs))
{
var dataLength = reader.ReadInt32();
if (reader.ReadInt32() == MetaEndMarker)
{
// go back end marker + length storage + data + version + start marker
fs.Seek(-(4 + 4 + dataLength + 4 + 4), SeekOrigin.Current);
try
{
return new ReplayMetadata(reader, path);
}
catch (InvalidOperationException ex)
{
Log.Write("debug", ex.ToString());
}
catch (NotSupportedException ex)
{
Log.Write("debug", ex.ToString());
}
}
}
return null;
}
static int WriteUtf8String(BinaryWriter writer, string text)
{
byte[] bytes;
if (!string.IsNullOrEmpty(text))
bytes = Encoding.UTF8.GetBytes(text);
else
bytes = new byte[0];
writer.Write(bytes.Length);
writer.Write(bytes);
return 4 + bytes.Length;
}
static string ReadUtf8String(BinaryReader reader)
{
return Encoding.UTF8.GetString(reader.ReadBytes(reader.ReadInt32()));
}
}
}