mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-15 13:14:17 +01:00
Add UIGlow and UIForeground SeString payloads; refactor some handling of integer markers in payloads, to make encoding a bit simpler
This commit is contained in:
parent
1e00a33577
commit
4c12b1dfb0
6 changed files with 186 additions and 32 deletions
|
|
@ -2,8 +2,6 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Dalamud.Game.Chat.SeStringHandling.Payloads;
|
using Dalamud.Game.Chat.SeStringHandling.Payloads;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
||||||
|
|
@ -74,6 +72,15 @@ namespace Dalamud.Game.Chat.SeStringHandling
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SeStringChunkType.UIForeground:
|
||||||
|
payload = new UIForegroundPayload();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SeStringChunkType.UIGlow:
|
||||||
|
payload = new UIGlowPayload();
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Log.Verbose("Unhandled SeStringChunkType: {0}", chunkType);
|
Log.Verbose("Unhandled SeStringChunkType: {0}", chunkType);
|
||||||
payload = new RawPayload((byte)chunkType);
|
payload = new RawPayload((byte)chunkType);
|
||||||
|
|
@ -104,7 +111,9 @@ namespace Dalamud.Game.Chat.SeStringHandling
|
||||||
|
|
||||||
protected enum SeStringChunkType
|
protected enum SeStringChunkType
|
||||||
{
|
{
|
||||||
Interactable = 0x27
|
Interactable = 0x27,
|
||||||
|
UIForeground = 0x48,
|
||||||
|
UIGlow = 0x49
|
||||||
}
|
}
|
||||||
|
|
||||||
protected enum EmbeddedInfoType
|
protected enum EmbeddedInfoType
|
||||||
|
|
@ -118,6 +127,9 @@ namespace Dalamud.Game.Chat.SeStringHandling
|
||||||
|
|
||||||
protected enum IntegerType
|
protected enum IntegerType
|
||||||
{
|
{
|
||||||
|
// Custom value indicating no marker at all
|
||||||
|
None = 0x0,
|
||||||
|
|
||||||
Byte = 0xF0,
|
Byte = 0xF0,
|
||||||
ByteTimes256 = 0xF1,
|
ByteTimes256 = 0xF1,
|
||||||
Int16 = 0xF2,
|
Int16 = 0xF2,
|
||||||
|
|
@ -188,37 +200,49 @@ namespace Dalamud.Game.Chat.SeStringHandling
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static byte[] MakeInteger(int value)
|
protected virtual byte[] MakeInteger(int value)
|
||||||
{
|
{
|
||||||
// clearly the epitome of efficiency
|
// single-byte values below the marker values have no marker and have 1 added
|
||||||
|
if (value + 1 < (int)IntegerType.Byte)
|
||||||
|
{
|
||||||
|
value++;
|
||||||
|
return new byte[] { (byte)value };
|
||||||
|
}
|
||||||
|
|
||||||
var bytesPadded = BitConverter.GetBytes(value);
|
var bytesPadded = BitConverter.GetBytes(value);
|
||||||
Array.Reverse(bytesPadded);
|
Array.Reverse(bytesPadded);
|
||||||
return bytesPadded.SkipWhile(b => b == 0x00).ToArray();
|
var shrunkValue = bytesPadded.SkipWhile(b => b == 0x00).ToArray();
|
||||||
|
|
||||||
|
var encodedNum = new List<byte>();
|
||||||
|
|
||||||
|
var marker = GetMarkerForIntegerBytes(shrunkValue);
|
||||||
|
if (marker != 0)
|
||||||
|
{
|
||||||
|
encodedNum.Add(marker);
|
||||||
|
}
|
||||||
|
|
||||||
|
encodedNum.AddRange(shrunkValue);
|
||||||
|
|
||||||
|
return encodedNum.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static IntegerType GetTypeForIntegerBytes(byte[] bytes)
|
// This is only accurate in a very general sense
|
||||||
|
// Different payloads seem to use different default values for things
|
||||||
|
// So this should be overridden where necessary
|
||||||
|
protected virtual byte GetMarkerForIntegerBytes(byte[] bytes)
|
||||||
{
|
{
|
||||||
// not the most scientific, exists mainly for laziness
|
// not the most scientific, exists mainly for laziness
|
||||||
|
|
||||||
if (bytes.Length == 1)
|
var marker = bytes.Length switch
|
||||||
{
|
{
|
||||||
return IntegerType.Byte;
|
1 => IntegerType.Byte,
|
||||||
}
|
2 => IntegerType.Int16,
|
||||||
else if (bytes.Length == 2)
|
3 => IntegerType.Int24,
|
||||||
{
|
4 => IntegerType.Int32,
|
||||||
return IntegerType.Int16;
|
_ => throw new NotSupportedException()
|
||||||
}
|
};
|
||||||
else if (bytes.Length == 3)
|
|
||||||
{
|
|
||||||
return IntegerType.Int24;
|
|
||||||
}
|
|
||||||
else if (bytes.Length == 4)
|
|
||||||
{
|
|
||||||
return IntegerType.Int32;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new NotSupportedException();
|
return (byte)marker;
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,14 @@ namespace Dalamud.Game.Chat.SeStringHandling
|
||||||
/// </summary>
|
/// </summary>
|
||||||
RawText,
|
RawText,
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// An SeString payload representing a text foreground color.
|
||||||
|
/// </summary>
|
||||||
|
UIForeground,
|
||||||
|
/// <summary>
|
||||||
|
/// An SeString payload representing a text glow color.
|
||||||
|
/// </summary>
|
||||||
|
UIGlow,
|
||||||
|
/// <summary>
|
||||||
/// An SeString payload representing any data we don't handle.
|
/// An SeString payload representing any data we don't handle.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Unknown
|
Unknown
|
||||||
|
|
|
||||||
|
|
@ -38,9 +38,7 @@ namespace Dalamud.Game.Chat.SeStringHandling.Payloads
|
||||||
var idBytes = MakeInteger(actualItemId);
|
var idBytes = MakeInteger(actualItemId);
|
||||||
bool hasName = !string.IsNullOrEmpty(ItemName);
|
bool hasName = !string.IsNullOrEmpty(ItemName);
|
||||||
|
|
||||||
var itemIdFlag = IsHQ ? IntegerType.Int16Plus1Million : IntegerType.Int16;
|
var chunkLen = idBytes.Length + 4;
|
||||||
|
|
||||||
var chunkLen = idBytes.Length + 5;
|
|
||||||
if (hasName)
|
if (hasName)
|
||||||
{
|
{
|
||||||
// 1 additional unknown byte compared to the nameless version, 1 byte for the name length, and then the name itself
|
// 1 additional unknown byte compared to the nameless version, 1 byte for the name length, and then the name itself
|
||||||
|
|
@ -54,8 +52,7 @@ namespace Dalamud.Game.Chat.SeStringHandling.Payloads
|
||||||
var bytes = new List<byte>()
|
var bytes = new List<byte>()
|
||||||
{
|
{
|
||||||
START_BYTE,
|
START_BYTE,
|
||||||
(byte)SeStringChunkType.Interactable, (byte)chunkLen, (byte)EmbeddedInfoType.ItemLink,
|
(byte)SeStringChunkType.Interactable, (byte)chunkLen, (byte)EmbeddedInfoType.ItemLink
|
||||||
(byte)itemIdFlag
|
|
||||||
};
|
};
|
||||||
bytes.AddRange(idBytes);
|
bytes.AddRange(idBytes);
|
||||||
// unk
|
// unk
|
||||||
|
|
@ -122,5 +119,16 @@ namespace Dalamud.Game.Chat.SeStringHandling.Payloads
|
||||||
ItemName = Encoding.UTF8.GetString(itemNameBytes);
|
ItemName = Encoding.UTF8.GetString(itemNameBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override byte GetMarkerForIntegerBytes(byte[] bytes)
|
||||||
|
{
|
||||||
|
// custom marker just for hq items?
|
||||||
|
if (bytes.Length == 3 && IsHQ)
|
||||||
|
{
|
||||||
|
return (byte)IntegerType.Int16Plus1Million;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.GetMarkerForIntegerBytes(bytes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,13 +35,11 @@ namespace Dalamud.Game.Chat.SeStringHandling.Payloads
|
||||||
public override byte[] Encode()
|
public override byte[] Encode()
|
||||||
{
|
{
|
||||||
var idBytes = MakeInteger(StatusId);
|
var idBytes = MakeInteger(StatusId);
|
||||||
var idPrefix = GetTypeForIntegerBytes(idBytes);
|
|
||||||
|
|
||||||
var chunkLen = idBytes.Length + 8;
|
var chunkLen = idBytes.Length + 7;
|
||||||
var bytes = new List<byte>()
|
var bytes = new List<byte>()
|
||||||
{
|
{
|
||||||
START_BYTE, (byte)SeStringChunkType.Interactable, (byte)chunkLen, (byte)EmbeddedInfoType.Status,
|
START_BYTE, (byte)SeStringChunkType.Interactable, (byte)chunkLen, (byte)EmbeddedInfoType.Status
|
||||||
(byte)idPrefix
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bytes.AddRange(idBytes);
|
bytes.AddRange(idBytes);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Dalamud.Game.Chat.SeStringHandling.Payloads
|
||||||
|
{
|
||||||
|
public class UIForegroundPayload : Payload
|
||||||
|
{
|
||||||
|
public override PayloadType Type => PayloadType.UIForeground;
|
||||||
|
|
||||||
|
public ushort RawColor { get; private set; }
|
||||||
|
|
||||||
|
//public int Red { get; private set; }
|
||||||
|
//public int Green { get; private set; }
|
||||||
|
//public int Blue { get; private set; }
|
||||||
|
|
||||||
|
public override byte[] Encode()
|
||||||
|
{
|
||||||
|
var colorBytes = MakeInteger(RawColor);
|
||||||
|
var chunkLen = colorBytes.Length + 1;
|
||||||
|
|
||||||
|
var bytes = new List<byte>(new byte[]
|
||||||
|
{
|
||||||
|
START_BYTE, (byte)SeStringChunkType.UIForeground, (byte)chunkLen
|
||||||
|
});
|
||||||
|
|
||||||
|
bytes.AddRange(colorBytes);
|
||||||
|
bytes.Add(END_BYTE);
|
||||||
|
|
||||||
|
return bytes.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Resolve()
|
||||||
|
{
|
||||||
|
// TODO: resolve color keys to hex colors via UIColor table
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{Type} - RawColor: {RawColor}";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ProcessChunkImpl(BinaryReader reader, long endOfStream)
|
||||||
|
{
|
||||||
|
RawColor = (ushort)GetInteger(reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override byte GetMarkerForIntegerBytes(byte[] bytes)
|
||||||
|
{
|
||||||
|
return bytes.Length switch
|
||||||
|
{
|
||||||
|
// a single byte of 0x01 is used to 'disable' color, and has no marker
|
||||||
|
1 => (byte)IntegerType.None,
|
||||||
|
_ => base.GetMarkerForIntegerBytes(bytes)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
58
Dalamud/Game/Chat/SeStringHandling/Payloads/UIGlowPayload.cs
Normal file
58
Dalamud/Game/Chat/SeStringHandling/Payloads/UIGlowPayload.cs
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Dalamud.Game.Chat.SeStringHandling.Payloads
|
||||||
|
{
|
||||||
|
public class UIGlowPayload : Payload
|
||||||
|
{
|
||||||
|
public override PayloadType Type => PayloadType.UIGlow;
|
||||||
|
|
||||||
|
public ushort RawColor { get; private set; }
|
||||||
|
|
||||||
|
//public int Red { get; private set; }
|
||||||
|
//public int Green { get; private set; }
|
||||||
|
//public int Blue { get; private set; }
|
||||||
|
|
||||||
|
public override byte[] Encode()
|
||||||
|
{
|
||||||
|
var colorBytes = MakeInteger(RawColor);
|
||||||
|
var chunkLen = colorBytes.Length + 1;
|
||||||
|
|
||||||
|
var bytes = new List<byte>(new byte[]
|
||||||
|
{
|
||||||
|
START_BYTE, (byte)SeStringChunkType.UIGlow, (byte)chunkLen
|
||||||
|
});
|
||||||
|
|
||||||
|
bytes.AddRange(colorBytes);
|
||||||
|
bytes.Add(END_BYTE);
|
||||||
|
|
||||||
|
return bytes.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Resolve()
|
||||||
|
{
|
||||||
|
// TODO: resolve color keys to hex colors via UIColor table
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{Type} - RawColor: {RawColor}";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ProcessChunkImpl(BinaryReader reader, long endOfStream)
|
||||||
|
{
|
||||||
|
RawColor = (ushort)GetInteger(reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override byte GetMarkerForIntegerBytes(byte[] bytes)
|
||||||
|
{
|
||||||
|
return bytes.Length switch
|
||||||
|
{
|
||||||
|
// a single byte of 0x01 is used to 'disable' color, and has no marker
|
||||||
|
1 => (byte)IntegerType.None,
|
||||||
|
_ => base.GetMarkerForIntegerBytes(bytes)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue