Skip to content

Instantly share code, notes, and snippets.

@veleek
Created October 3, 2017 19:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save veleek/02da685ebc19f4f33a12fc76b887e867 to your computer and use it in GitHub Desktop.
Save veleek/02da685ebc19f4f33a12fc76b887e867 to your computer and use it in GitHub Desktop.
LinqPad script to load a Level.dat file from Minecraft Better Together
void Main()
{
string path = @"Path to your Level.dat";
Level l = new Level();
try
{
l.ReadFrom(File.OpenRead(path));
}
catch (Exception e)
{
e.Dump();
}
l.Dump();
}
public class Level
{
public const int HeaderLength = 8;
public int Version { get; set; }
public Dictionary<string, object> Properties { get; set; }
public Level()
{
}
public void ReadFrom(Stream stream)
{
using (BinaryReader reader = new BinaryReader(stream))
{
ReadFrom(reader);
}
}
public void ReadFrom(BinaryReader reader)
{
Version = reader.ReadInt32(false);
int objectLength = reader.ReadInt32(false);
if (reader.BaseStream.Length != objectLength + HeaderLength)
{
throw new Exception("Stream is longer than expected");
}
this.Properties = this.ReadRoot(reader);
if (reader.BaseStream.Position != reader.BaseStream.Length)
{
throw new Exception("Additional data left in object");
}
}
public Dictionary<string, object> ReadRoot(BinaryReader reader)
{
string name;
object value;
if (!ReadProperty(reader, out name, out value))
{
throw new Exception("Unable to read root.");
}
return value as Dictionary<string, object>;
}
public bool ReadProperty(BinaryReader reader, out string name, out object value)
{
TagType type = ReadType(reader);
if (type == TagType.None)
{
name = null;
value = null;
return false;
}
name = ReadString(reader);
try
{
switch (type)
{
case TagType.None:
value = null;
return false;
case TagType.Boolean:
value = reader.ReadBoolean();
break;
case TagType.Int16:
value = reader.ReadInt16(false);
break;
case TagType.Int32:
value = reader.ReadInt32(false);
break;
case TagType.Int64:
value = reader.ReadInt64(false);
break;
case TagType.String:
value = ReadString(reader);
break;
case TagType.Float:
value = reader.ReadSingle();
break;
case TagType.Array:
if (name == "lastOpenedWithVersion")
{
value = reader.ReadBytes(0x15);
}
else
{
value = reader.ReadBytes(5);
}
break;
case TagType.Object:
value = ReadObject(reader);
break;
default:
throw new Exception($"Unknown property of type '{type}'.");
}
}
catch (Exception e)
{
throw new Exception($"Error while reading property '{name}'.", e);
}
return true;
}
public Dictionary<string, object> ReadObject(BinaryReader reader)
{
Dictionary<string, object> properties = new Dictionary<string, object>();
try
{
string name;
object value;
while (ReadProperty(reader, out name, out value))
{
properties.Add(name, value);
}
}
catch (Exception e)
{
Exception ne = new Exception("Error while reading object", e);
foreach (var p in properties)
{
ne.Data.Add(p.Key, p.Value);
}
throw ne;
}
return properties;
}
public DateTime ReadDateTime(BinaryReader reader)
{
DateTime unixEpoch = new DateTime(1970, 01, 01);
Int64 unixTimestamp = reader.ReadInt64(false);
return unixEpoch.AddSeconds(unixTimestamp);
}
public string ReadString(BinaryReader reader)
{
int length = reader.ReadInt16(false);
byte[] bytes = reader.ReadBytes(length);
return Encoding.ASCII.GetString(bytes);
}
public TagType ReadType(BinaryReader reader)
{
return (TagType)reader.ReadByte();
}
public enum TagType
{
None,
Boolean = 0x01,
Int16 = 0x02,
Int32 = 0x03,
Int64 = 0x04,
Float = 0x05,
String = 0x08,
Array = 0x09,
Object = 0x0A,
}
}
public static class BinaryReaderExtensions
{
public static byte[] ReadBytes(this BinaryReader reader, int count, bool bigEndian)
{
byte[] bytes = reader.ReadBytes(count);
if (bigEndian)
{
Array.Reverse(bytes);
}
return bytes;
}
public static Int32 ReadInt32(this BinaryReader reader, bool bigEndian)
{
return BitConverter.ToInt32(reader.ReadBytes(sizeof(Int32), bigEndian), 0);
}
public static Int16 ReadInt16(this BinaryReader reader, bool bigEndian)
{
return BitConverter.ToInt16(reader.ReadBytes(sizeof(Int16), bigEndian), 0);
}
public static Int64 ReadInt64(this BinaryReader reader, bool bigEndian)
{
return BitConverter.ToInt64(reader.ReadBytes(sizeof(Int64), bigEndian), 0);
}
}
// Define other methods and classes here
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment