Level Entity (LENT) Section - Troodon80/Summoner-Save-File-Editor GitHub Wiki
Contains data for player characters and other creatures:
Field | Offset | Size | Description |
---|---|---|---|
Signature | 0x00027667 | 4 bytes | "LENT" ASCII string |
FirstEntityOffset | +0x04 | 4 bytes | Relative offset to first entity |
EndRegionOffset | +0x08 | 4 bytes | Relative offset to end of entity region |
PossibleBitfield | +0x0C | 4 bytes | Bitfield or mask? |
PossibleSaveId | +0x10 | 4 bytes | Possibly a global save ID/hash? |
PossibleMaxEntitySpan | +0x14 | 4 bytes | Maybe max entity span? |
PossibleCodeRef1 | +0x18 | 4 bytes | Code address or data reference? |
PossibleCodeRef2 | +0x1C | 4 bytes | Code address or data reference? |
PossibleDataTable | +0x20 | 4 bytes | Likely data table or pointer? |
PossibleFuncAddr1 | +0x24 | 4 bytes | Function address? |
PossibleFuncAddr2 | +0x28 | 4 bytes | Function address? |
PossibleFuncAddr3 | +0x2C | 4 bytes | Function address? |
EntityCount | +0x30 | 4 bytes | Number of characters and creatures |
Character/Creature Data | +0x34 | Variable | Individual character and creature data starts here |
Each entity contains:
Both character and creature entities begin with the same header structure:
Field | Offset | Size | Description |
---|---|---|---|
Creature Hash | +0x00 | 4 bytes | String-hash identifier |
Creature Type | +0x04 | 4 bytes | Type identifier (7 = Character, other values = Creature/NPC) |
Char/Cre block data follows | +0x08 | 4 bytes | See tables for type 7 and non-type 7 immediately following |
Characters (Joseph, Flece, Rosalind, Jekhar) have the following structure:
Field | Offset | Size | Description |
---|---|---|---|
Position X | 0x00 | 4 bytes | X coordinate (float) |
Position Z | 0x04 | 4 bytes | Z coordinate (float) |
Position Y | 0x08 | 4 bytes | Y coordinate (float) |
Rotation | 0x0C | 4 bytes | Rotation angle (float) |
Status Triplets | 0x10 | 84 bytes | 7 sets of three integers (IntTriple). I believe this is status and maybe AI related. Modifying this section has had some rather odd effects—mostly just character getting -Blind when loading, but occasionally Rosalind gets punted and knocked down by nothing. I have no clue how these are parsed. |
Spare Int | 0x64 | 4 bytes | Additional integer value |
Equipped Items | 0x68 | 36 bytes | 9 equipment slots (4 bytes each): |
Amulet | |||
Ring 1 | |||
Ring 2 | |||
Gauntlets | |||
Boots | |||
Weapon | |||
Shield | |||
Torso | |||
Leggings | |||
Unmapped Block | 0x8C | 144 bytes | 36 integers of unmapped data |
Hand to Hand | 0x11C | 1 byte | Hand to Hand skill level (unused since you can't unequip your weapon. Actually shows up in-game, though it has no icon. Almost certainly left over from early builds or concepts which apparently also included concepts for things like forging and mining) |
Unknown Skill 1 | 0x11D | 1 byte | Unknown character skill |
Character Speed | 0x11E | 1 byte | Movement/action speed |
Sword | 0x11F | 1 byte | Sword skill level |
Axe | 0x120 | 1 byte | Axe skill level |
Blunt | 0x121 | 1 byte | Blunt weapon skill level |
Staff | 0x122 | 1 byte | Staff skill level |
Bow | 0x123 | 1 byte | Bow skill level |
Heavy Arms | 0x124 | 1 byte | Heavy weapons skill level |
Parry | 0x125 | 1 byte | Parry skill level |
Counter Attack | 0x126 | 1 byte | Counter Attack skill level |
Dodge | 0x127 | 1 byte | Dodge skill level |
Critical Hit | 0x128 | 1 byte | Critical Hit skill level |
Double Attack | 0x129 | 1 byte | Double Attack skill level |
Push | 0x12A | 1 byte | Push skill level |
Kick | 0x12B | 1 byte | Kick skill level |
Trip | 0x12C | 1 byte | Trip skill level |
Aimed Attack | 0x12D | 1 byte | Aimed Attack skill level |
Backstab | 0x12E | 1 byte | Backstab skill level |
Assess | 0x12F | 1 byte | Assess skill level |
Appraise | 0x130 | 1 byte | Appraise skill level |
Picklock | 0x131 | 1 byte | Picklock skill level |
Sneak | 0x132 | 1 byte | Sneak skill level |
Hide | 0x133 | 1 byte | Hide skill level |
Unknown Skills | 0x134 | 3 bytes | 3 unknown skill bytes |
Summon | 0x137 | 1 byte | Summon skill level |
Heal | 0x138 | 1 byte | Heal magic skill level |
Dark | 0x139 | 1 byte | Dark magic skill level |
Energy | 0x13A | 1 byte | Energy magic skill level |
Holy | 0x13B | 1 byte | Holy magic skill level |
Fire | 0x13C | 1 byte | Fire magic skill level |
Ice | 0x13D | 1 byte | Ice magic skill level |
Unknown Skill 3 | 0x13E | 1 byte | Unknown skill |
Magic Resist | 0x13F | 1 byte | Magic resistance skill level |
Character Level | 0x140 | 2 bytes | Character level (short) |
Experience | 0x142 | 4 bytes | Character experience points |
Current HP | 0x146 | 4 bytes | Current hit points (float) |
Base HP | 0x14A | 4 bytes | Maximum hit points (float) |
Current AP | 0x14E | 2 bytes | Current ability points (short) |
Base AP | 0x150 | 2 bytes | Maximum ability points (short) |
Unknown Value | 0x152 | 4 bytes | Unknown purpose |
AI Value | 0x156 | 4 bytes | AI behavior control value |
Unmapped Character Data | 0x15A | 34 bytes | Additional unmapped character data |
Skill Points | 0x17C | 4 bytes | Available skill points |
Note: Skills are 0-10 in-game, but stored as a multiple of 10. 5 becomes 50, 10 becomes 100, 25 becomes 250 (which would be the maximum here since it's only a byte).
Non-player creatures (enemies, monsters, NPCs) have the following structure:
Field | Offset | Size | Description |
---|---|---|---|
Position X | 0x00 | 4 bytes | X coordinate (float) |
Position Z | 0x04 | 4 bytes | Z coordinate (float) |
Position Y | 0x08 | 4 bytes | Y coordinate (float) |
Rotation | 0x0C | 4 bytes | Rotation angle (float) |
Maybe Status Related? | 0x10 | 88 bytes | Array of 22 status integers |
Creature Level | 0x68 | 2 bytes | Creature level (short) |
Current HP | 0x6A | 4 bytes | Current hit points (float) |
Base HP | 0x6E | 4 bytes | Maximum hit points (float) |
Current AP | 0x72 | 2 bytes | Current ability points (short) |
Base AP | 0x74 | 2 bytes | Maximum ability points (short) |
Unknown Value | 0x76 | 4 bytes | Unknown purpose integer |
AI Value | 0x7A | 4 bytes | AI behavior control value |
Memory Block | 0x7E | 248 bytes | Array of 62 integers, possibly memory/pointer related? |
Unknown/Padding | 0x176 | 2 bytes | Unknown end value (short) |
Note: As previously mentioned, there is a section immediately following the main series of character/creature blocks that follows a pattern of count+hash and appears to be entity linking. I'm not doing anything with this block, but a proof of concept parser is as follows:
Click to expand...
public class LentRelatedBlock
{
public static long CurrentPosition = 0;
public class Entry
{
public uint EntityHash { get; set; }
public List<uint> RelatedHashes { get; set; } = new();
public int TrailingInt { get; set; }
}
public static List<Entry> ReadFromStream(BinaryReader reader, int offset, int baseOffset)
{
var entries = new List<Entry>();
reader.BaseStream.Seek(offset, SeekOrigin.Begin);
int outerCount = reader.ReadInt32();
for (int i = 0; i < outerCount; i++)
{
uint entityHash = reader.ReadUInt32();
if (entityHash == 0)
continue;
int innerCount = reader.ReadInt32();
var related = new List<uint>();
for (int j = 0; j < innerCount; j++)
{
uint relatedHash = reader.ReadUInt32();
if (relatedHash != 0)
related.Add(relatedHash);
}
int unknownTrailingInt = reader.ReadInt32();
entries.Add(new Entry
{
EntityHash = entityHash,
RelatedHashes = related,
UnknownInt = unknownTrailingInt
});
}
CurrentPosition = reader.BaseStream.Position;
return entries;
}
public static List<Entry> ReadFromFile(string path, int offset, int baseOffset)
{
using var stream = File.OpenRead(path);
using var reader = new BinaryReader(stream);
return ReadFromStream(reader, offset, baseOffset);
}
}
Not that this does not parse to the beginning of the CMRA block. There is still more data to be read. I just don't know how yet or what it does, it's covered by le_size, so I'd guess it's more entity-related data. However, it's not read in a linear sequence as far as I can see.