Skip to content

Commit

Permalink
Merge pull request #83 from Xeeynamo/feature/bbs-ctd-editor
Browse files Browse the repository at this point in the history
BBS CTD and Font support
  • Loading branch information
Rikux3 authored Feb 28, 2020
2 parents b4b1167 + 6b9d148 commit 1181409
Show file tree
Hide file tree
Showing 48 changed files with 2,260 additions and 8 deletions.
201 changes: 201 additions & 0 deletions OpenKh.Bbs/Ctd.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
using OpenKh.Bbs.Messages;
using OpenKh.Common;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Xe.BinaryMapper;

namespace OpenKh.Bbs
{
public class Ctd
{
private const int MagicCode = 0x44544340;
private const int Version = 1;
private const int HeaderLength = 0x20;
private const int Entry1Length = 0xC;
private const int Entry2Length = 0x20;

private class Header
{
[Data] public int MagicCode { get; set; }
[Data] public int Version { get; set; }
[Data] public short Unknown08 { get; set; }
[Data] public short Unknown0a { get; set; }
[Data] public short LayoutCount { get; set; }
[Data] public short MessageCount { get; set; }
[Data] public int MessageOffset { get; set; }
[Data] public int LayoutOffset { get; set; }
[Data] public int TextOffset { get; set; }
[Data] public int Unknown1c { get; set; }
}

private class _Message
{
[Data] public short Id { get; set; }
[Data] public short Unknown02 { get; set; }
[Data] public int Offset { get; set; }
[Data] public int Entry2Index { get; set; }
}

public class Message
{
public short Id { get; set; }
public short Unknown02 { get; set; }
public int LayoutIndex { get; set; }

public byte[] Data { get; set; }

public string Text
{
get => CtdEncoders.International.ToText(Data);
set => Data = CtdEncoders.International.FromText(value);
}

public override string ToString() =>
$"{Id:X04} {Unknown02:X04} {LayoutIndex:X08}: {Text}";
}

public class Layout
{
[Data] public ushort DialogX { get; set; }
[Data] public ushort DialogY { get; set; }
[Data] public ushort DialogWidth { get; set; }
[Data] public ushort DialogHeight { get; set; }
[Data] public byte DialogAlignment { get; set; }
[Data] public byte DialogBorders { get; set; }
[Data] public byte TextAlignment { get; set; }
[Data] public byte Unknown0b { get; set; }
[Data] public ushort FontSize { get; set; }
[Data] public ushort HorizontalSpace { get; set; }
[Data] public ushort VerticalSpace { get; set; }
[Data] public ushort TextX { get; set; }
[Data] public ushort TextY { get; set; }
[Data] public ushort DialogHook { get; set; }
[Data] public ushort DialogHookX { get; set; }
[Data] public ushort Unknown1a { get; set; }
[Data] public ushort Unknown1c { get; set; }
[Data] public ushort Unknown1e { get; set; }
}

public short Unknown { get; set; }
public List<Message> Messages { get; set; }
public List<Layout> Layouts { get; set; }

public string GetString(int id)
{
var entry = Messages.FirstOrDefault(x => x.Id == id);
if (entry == null)
return null;

return entry.Text;
}

public void Write(Stream stream)
{
var messageOffset = HeaderLength;
var layoutOffset = Helpers.Align(messageOffset + Messages.Count * Entry1Length, 16);
var textOffset = layoutOffset + Layouts.Count * Entry2Length;

BinaryMapping.WriteObject(stream, new Header
{
MagicCode = MagicCode,
Version = Version,
Unknown08 = 0,
Unknown0a = Unknown,
LayoutCount = (short)Layouts.Count,
MessageCount = (short)Messages.Count,
MessageOffset = messageOffset,
LayoutOffset = layoutOffset,
TextOffset = textOffset,
Unknown1c = 0,
});

stream.Position = messageOffset;
var textStream = new MemoryStream(4096);
var nextTextOffset = textOffset;
foreach (var item in Messages)
{
textStream.Write(item.Data, 0, item.Data.Length);
textStream.WriteByte(0);

BinaryMapping.WriteObject(stream, new _Message
{
Id = item.Id,
Unknown02 = item.Unknown02,
Offset = nextTextOffset,
Entry2Index = item.LayoutIndex
});

nextTextOffset += item.Data.Length + 1;
}

stream.Position = layoutOffset;
foreach (var item in Layouts)
BinaryMapping.WriteObject(stream, item);

stream.Position = textOffset;
foreach (var entry in Messages)
{
stream.Write(entry.Data, 0, entry.Data.Length);
stream.WriteByte(0);
}
}

public Ctd()
{
Unknown = 0;
Messages = new List<Message>();
Layouts = new List<Layout>();
}

private Ctd(Stream stream)
{
var header = BinaryMapping.ReadObject<Header>(stream);
Unknown = header.Unknown0a;

stream.Position = header.MessageOffset;
var textEntries = Enumerable.Range(0, header.MessageCount)
.Select(x => BinaryMapping.ReadObject<_Message>(stream))
.ToList();

stream.Position = header.LayoutOffset;
Layouts = Enumerable.Range(0, header.LayoutCount)
.Select(x => BinaryMapping.ReadObject<Layout>(stream))
.ToList();

Messages = textEntries
.Select(x =>
{
stream.SetPosition(x.Offset);
return new Message
{
Id = x.Id,
Unknown02 = x.Unknown02,
LayoutIndex = x.Entry2Index,
Data = ReadUntilTerminator(stream)
};
}).ToList();
}

private byte[] ReadUntilTerminator(Stream stream)
{
var byteList = new List<byte>(100);

while (stream.Position < stream.Length)
{
var ch = stream.ReadByte();
if (ch <= 0)
break;

byteList.Add((byte)ch);
}

return byteList.ToArray();
}

public static Ctd Read(Stream stream) => new Ctd(stream.SetPosition(0));

public static bool IsValid(Stream stream) =>
new BinaryReader(stream.SetPosition(0)).ReadInt32() == MagicCode;
}
}
36 changes: 36 additions & 0 deletions OpenKh.Bbs/FontCharacterInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.Collections.Generic;
using System.IO;
using Xe.BinaryMapper;

namespace OpenKh.Bbs
{
public class FontCharacterInfo
{
[Data] public ushort Id { get; set; }
[Data] public ushort PositionX { get; set; }
[Data] public ushort PositionY { get; set; }
[Data] public byte Palette { get; set; }
[Data] public byte Width { get; set; }

public static FontCharacterInfo[] Read(Stream stream)
{
var characterCount = (int)stream.Length / 8;
var charactersInfo = new FontCharacterInfo[characterCount];
stream.Position = 0;

for (var i = 0; i < characterCount; i++)
charactersInfo[i] = BinaryMapping.ReadObject<FontCharacterInfo>(stream);

return charactersInfo;
}

public static void Write(Stream stream, IEnumerable<FontCharacterInfo> charactersInfo)
{
stream.Position = 0;
foreach (var info in charactersInfo)
BinaryMapping.WriteObject(stream, info);

stream.SetLength(stream.Position);
}
}
}
59 changes: 59 additions & 0 deletions OpenKh.Bbs/FontIconInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using OpenKh.Common;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Xe.BinaryMapper;

namespace OpenKh.Bbs
{
public class FontIconInfo
{
public ushort Key { get; set; }
public byte Left { get; set; }
public byte Top { get; set; }
public byte Right { get; set; }
public byte Bottom { get; set; }

private class MetaIcon
{
[Data] public ushort Key { get; set; }
[Data] public byte Left { get; set; }
[Data] public byte Top { get; set; }
[Data] public byte Right { get; set; }
[Data] public byte Bottom { get; set; }
[Data] public short RESERVED { get; set; }
}

public static IEnumerable<FontIconInfo> Read(Stream stream)
{
var count = stream.ReadInt32();
return Enumerable.Range(0, count)
.Select(_ => BinaryMapping.ReadObject<MetaIcon>(stream))
.Select(x => new FontIconInfo
{
Key = x.Key,
Left = x.Left,
Top = x.Top,
Right = x.Right,
Bottom = x.Bottom
})
.ToArray();
}

public static void Write(Stream stream, IEnumerable<FontIconInfo> fontIconsInfo)
{
var myFontIconsInfo = fontIconsInfo.ToArray();
stream.Write(myFontIconsInfo.Length);
foreach (var info in myFontIconsInfo)
BinaryMapping.WriteObject(stream, new MetaIcon
{
Key = info.Key,
Left = info.Left,
Top = info.Top,
Right = info.Right,
Bottom = info.Bottom,
RESERVED = 0
});
}
}
}
20 changes: 20 additions & 0 deletions OpenKh.Bbs/FontInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System.IO;
using Xe.BinaryMapper;

namespace OpenKh.Bbs
{
public class FontInfo
{
[Data] public short CharacterCount { get; set; }
[Data] public short ImageWidth { get; set; }
[Data] public short MaxImageHeight { get; set; }
[Data] public byte CharacterWidth { get; set; }
[Data] public byte CharacterHeight { get; set; }

public static FontInfo Read(Stream stream) =>
BinaryMapping.ReadObject<FontInfo>(stream);

public void Write(Stream stream) =>
BinaryMapping.WriteObject(stream, this);
}
}
Loading

0 comments on commit 1181409

Please sign in to comment.