Level Entity (LENT) Section - Troodon80/Summoner-Save-File-Editor GitHub Wiki

Level Entity (LENT) Section

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

Character Data

Each entity contains:

Common Header Structure

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

Character Block (Type 7)

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).

Creature Block (Non-Type 7; Type 4, 5, 6, etc.)

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.

⚠️ **GitHub.com Fallback** ⚠️