Welcome
Ladies and Gents:

These forums are now closed and registration disabled.

Please join us at our new forum on Proboards. Our hope is that these new forums are more stable, provide more and better features, and allow continuation of the project forums in a safer, more secure, long term environment.

me3explorer.proboards.com

--The ME3Explorer Team

Done Research: Plot Manager Native Objects

Technical research related to the structure of Mass Effect game files.

Done Research: Plot Manager Native Objects

Postby TankMaster » 22 May 2014, 20:06

I am not sure if anyone has already done this in detail or not, but I have determined the properties to the plot manager native objects. Those being the Quest Maps, Codex Maps and State Transition Maps.

If you are starting from the absolute beginning of the data, you have 3 integers before the map data: packageExportIndex, propertyNameIndex and propertyNameFlags.

This is the pseudo code for all the objects:

Shared types:
Code: Select all
struct BioVersionedNativeObject
    int InstanceVersion


BioCodexMap:
Code: Select all
struct BioCodexEntry : BioVersionedNativeObject
    int Id
    // InstanceVersion
    int Title
    int Description
    int TextureIndex
    int Priority
    int CodexSound // If InstanceVersion is 4 or higher, otherwise it is not present

struct BioCodexPage : BioCodexEntry
    int Section

struct BioCodexSection : BioCodexEntry
    int IsPrimary // bool

class BioCodexMap
    int SectionsCount
    Dictionary<int, BioCodexSection> Sections
   
    int PagesCount
    Dictionary<int, BioCodexPage> Pages


BioQuestMap:
Code: Select all
struct BioPlotItem : BioVersionedNativeObject
    // InstanceVersion
    int Name
    int IconIndex
    int Conditional
    int State
    int TargetItems

struct BioQuest : BioVersionedNativeObject
    int Id
    // InstanceVersion
    int IsMission // bool
   
    int GoalsCount
    List<BioQuestGoal> Goals
   
    int TasksCount
    List<BioQuestTask> Tasks
   
    int PlotItemsCount
    List<BioQuestPlotItem> PlotItems

struct BioQuestGoal : BioVersionedNativeObject
    // InstanceVersion
    int Name
    int Description
    int Conditional
    int State

struct BioQuestTask : BioVersionedNativeObject
    // InstanceVersion
    int QuestCompleteTask
    int Name
    int Description
   
    int PlotItemIndicesCount
    List<int> PlotItemIndices
   
    long Planet // UName
   
    int WaypointTagSize
    char WaypointTag[WaypointTagSize]

class BioQuestMap
    int QuestsCount
    Dictionary<int, BioQuest> Quests


BioStateMap:
Code: Select all
struct BioStateEvent : BioVersionedNativeObject
    int Id
    // InstanceVersion
   
    int EventElementsCount
    List<BioStateEventElement> Elements

struct BioStateEventElement : BioVersionedNativeObject
    StateEventElementType ElementType
    // InstanceVersion

struct BioStateEventElementBool : BioStateEventElement
    int GlobalBool
    int NewState // bool
    int UseParam // bool

struct BioStateEventElementConsequence : BioStateEventElement
    int Consequence

struct BioStateEventElementFloat : BioStateEventElement
    int GlobalFloat
    float NewValue
    int UseParam // bool
    int Increment // bool

struct BioStateEventElementFunction : BioStateEventElement
    long FunctionPackage // UName
    long FunctionClass // UName
    long FunctionName // UName
    int Parameter

struct BioStateEventElementInt : BioStateEventElement
    int GlobalInt
    int NewValue
    int UseParam // bool
    int Increment // bool

struct BioStateEventElementLocal : BioStateEventElement
    int ObjectTag
    int FunctionName
    int ObjectType
    int UseParam // bool

struct BioStateEventElementLocalBool : BioStateEventElementLocal
    int NewValue // bool

struct BioStateEventElementLocalFloat : BioStateEventElementLocal
    float NewValue

struct BioStateEventElementLocalInt : BioStateEventElementLocal
    int NewValue

struct BioStateEventElementSubstate : BioStateEventElement
    int GlobalBool
    int ParentIndex
    int NewState // bool
    int UseParam // bool
    int ParentTypeOr // bool
   
    int SiblingIndicesCount
    List<int> SiblingIndices

class BioStateMap
    int EventElementsCount
    Dictionary<int, BioStateEventElement> StateEvents

enum StateEventElementType
    Bool = 0
    Consequence = 1
    Float = 2
    Function = 3
    Int = 4
    LocalBool = 5
    LocalFloat = 6
    LocalInt = 7
    Substate = 8
    Max = 9



This is the C# code I have made for reading the map data.

Shared types:
Code: Select all
public abstract class BioVersionedNativeObject
{
    protected BioVersionedNativeObject()
    {
        InstanceVersion = 0;
    }

    protected BioVersionedNativeObject(BinaryReader reader)
    {
        if (reader == null)
        {
            throw new ArgumentNullException("reader");
        }

        // Disabled because some objects have an id infront of the InstanceVersion value
        //InstanceVersion = reader.ReadInt32();
    }

    public int InstanceVersion { get; set; }
}


BioCodexMap:
Code: Select all
// Codex entry
public class BioCodexEntry : BioVersionedNativeObject
{
    public BioCodexEntry(BinaryReader reader)
        : base(reader)
    {
        Id = reader.ReadInt32();
        InstanceVersion = reader.ReadInt32();
        Title = reader.ReadInt32();
        Description = reader.ReadInt32();
        TextureIndex = reader.ReadInt32();
        Priority = reader.ReadInt32();

        CodexSound = InstanceVersion == 4 ? reader.ReadInt32() : null;
    }

    //class UWwiseEvent*
    // Points to export entry, otherwise it's 0
    public int? CodexSound { get; set; }

    public UStringRef Description { get; set; }

    public int Id { get; set; }

    public int Priority { get; set; }

    public int TextureIndex { get; set; }

    public UStringRef Title { get; set; }
}

// Codex page
public class BioCodexPage : BioCodexEntry
{
    public BioCodexPage(BinaryReader reader)
        : base(reader)
    {
        Section = reader.ReadInt32();
    }

    public int Section { get; set; }
}

// Codex section
public class BioCodexSection : BioCodexEntry
{
    public BioCodexSection(BinaryReader reader)
        : base(reader)
    {
        IsPrimary = Convert.ToBoolean(reader.ReadInt32());
    }

    public bool IsPrimary { get; set; }
}

// Map of the codices
public class BioCodexMap
{
    public BioCodexMap(BinaryReader reader)
    {
        reader.Seek(0);

        var packageExportIndex = reader.ReadInt32();
        UName propertyName = reader.ReadInt64();

        // Sections
        var sectionsCount = reader.ReadInt32();
        Sections = new Dictionary<int, BioCodexSection>();

        for (var i = 0; i < sectionsCount; i++)
        {
            var section = new BioCodexSection(reader);

            Sections.Add(section.Id, section);
        }

        // Pages
        var pagesCount = reader.ReadInt32();
        Pages = new Dictionary<int, BioCodexPage>();

        for (var i = 0; i < pagesCount; i++)
        {
            var page = new BioCodexPage(reader);

            Pages.Add(page.Id, page);
        }
    }

    public Dictionary<int, BioCodexPage> Pages { get; set; }

    public Dictionary<int, BioCodexSection> Sections { get; set; }
}


BioQuestMap:
Code: Select all
// Quest goal
public class BioQuestGoal : BioVersionedNativeObject
{
    public BioQuestGoal(BinaryReader reader)
        : base(reader)
    {
        InstanceVersion = reader.ReadInt32();
        Name = reader.ReadInt32();
        Description = reader.ReadInt32();
        Conditional = reader.ReadInt32();
        State = reader.ReadInt32();
    }

    public int Conditional { get; set; }

    public UStringRef Description { get; set; }

    public int Id { get; set; }

    public UStringRef Name { get; set; }

    public int State { get; set; }
}

// Quest task
public class BioQuestTask : BioVersionedNativeObject
{
    public BioQuestTask(BinaryReader reader)
        : base(reader)
    {
        InstanceVersion = reader.ReadInt32();
        QuestCompleteTask = Convert.ToBoolean(reader.ReadInt32());
        Name = reader.ReadInt32();
        Description = reader.ReadInt32();

        var plotItemIndicesCount = reader.ReadInt32();
        PlotItemIndices = new List<int>();

        for (var i = 0; i < plotItemIndicesCount; i++)
        {
            PlotItemIndices.Add(reader.ReadInt32());
        }

        Planet = reader.ReadInt64();

        var waypointTagSize = reader.ReadInt32();

        if (waypointTagSize <= 0)
        {
            return;
        }

        var chars = reader.ReadChars(waypointTagSize);
        WaypointTag = new string(chars);
    }

    public UStringRef Description { get; set; }

    public int Id { get; set; }

    public UStringRef Name { get; set; }

    public UName Planet { get; set; }

    public List<int> PlotItemIndices { get; set; }

    public bool QuestCompleteTask { get; set; }

    public string WaypointTag { get; set; }
}

// Quest plot item
public class BioPlotItem : BioVersionedNativeObject
{
    public BioPlotItem(BinaryReader reader)
        : base(reader)
    {
        InstanceVersion = reader.ReadInt32();
        Name = reader.ReadInt32();
        IconIndex = reader.ReadInt32();
        Conditional = reader.ReadInt32();
        State = reader.ReadInt32();
        TargetItems = reader.ReadInt32();
    }

    public int Conditional { get; set; }

    public int IconIndex { get; set; }

    public int Id { get; set; }

    public UStringRef Name { get; set; }

    public int State { get; set; }

    public int TargetItems { get; set; }
}

// Quest
public class BioQuest : BioVersionedNativeObject
{
    public BioQuest(BinaryReader reader)
        : base(reader)
    {
        Id = reader.ReadInt32();
        InstanceVersion = reader.ReadInt32();
        IsMission = Convert.ToBoolean(reader.ReadInt32());

        // Goals
        var goalsCount = reader.ReadInt32();
        Goals = new List<BioQuestGoal>();

        for (var i = 0; i < goalsCount; i++)
        {
            var goal = new BioQuestGoal(reader);

            Goals.Add(goal);
        }

        // Tasks
        var tasksCount = reader.ReadInt32();
        Tasks = new List<BioQuestTask>();

        for (var i = 0; i < tasksCount; i++)
        {
            var task = new BioQuestTask(reader);

            Tasks.Add(task);
        }

        // Plot Items
        var plotItemsCount = reader.ReadInt32();
        PlotItems = new List<BioPlotItem>();

        for (var i = 0; i < plotItemsCount; i++)
        {
            var plotItem = new BioPlotItem(reader);

            PlotItems.Add(plotItem);
        }
    }

    public List<BioQuestGoal> Goals { get; set; }

    public int Id { get; set; }

    public bool IsMission { get; set; }

    public List<BioPlotItem> PlotItems { get; set; }

    public List<BioQuestTask> Tasks { get; set; }
}

// Quest map
public class BioQuestMap
{
    public BioQuestMap(BinaryReader reader)
    {
        reader.Seek(0);

        var packageExportIndex = reader.ReadInt32();
        UName propertyName = reader.ReadInt64();

        var questsCount = reader.ReadInt32();
        Quests = new Dictionary<int, BioQuest>();

        for (var i = 0; i < questsCount; i++)
        {
            var quest = new BioQuest(reader);

            Quests.Add(quest.Id, quest);
        }
    }

    public Dictionary<int, BioQuest> Quests { get; set; }
}


BioStateMap:
Code: Select all
public class BioStateEvent : BioVersionedNativeObject
{
    public BioStateEvent(List<BioStateEventElement> elements = null)
    {
        Elements = elements ?? new List<BioStateEventElement>();
    }

    public BioStateEvent(BinaryReader reader)
        : base(reader)
    {
        Id = reader.ReadInt32();
        InstanceVersion = reader.ReadInt32();

        var eventElementsCount = reader.ReadInt32();
        Elements = new List<BioStateEventElement>();

        for (var i = 0; i < eventElementsCount; i++)
        {
            var elementType = (StateEventElementType) reader.ReadInt32();
            BioStateEventElement element;

            switch (elementType)
            {
                case StateEventElementType.Bool:
                {
                    element = new BioStateEventElementBool(reader);

                    break;
                }
                case StateEventElementType.Consequence:
                {
                    element = new BioStateEventElementConsequence(reader);

                    break;
                }
                case StateEventElementType.Float:
                {
                    element = new BioStateEventElementFloat(reader);

                    break;
                }
                case StateEventElementType.Function:
                {
                    element = new BioStateEventElementFunction(reader);

                    break;
                }
                case StateEventElementType.Int:
                {
                    element = new BioStateEventElementInt(reader);

                    break;
                }
                case StateEventElementType.LocalBool:
                {
                    element = new BioStateEventElementLocalBool(reader);

                    break;
                }
                case StateEventElementType.LocalFloat:
                {
                    element = new BioStateEventElementLocalFloat(reader);

                    break;
                }
                case StateEventElementType.LocalInt:
                {
                    element = new BioStateEventElementLocalInt(reader);

                    break;
                }
                case StateEventElementType.Substate:
                {
                    element = new BioStateEventElementSubstate(reader);

                    break;
                }
                case StateEventElementType.Max:
                {
                    throw new ArgumentOutOfRangeException();
                }
                default:
                {
                    throw new ArgumentOutOfRangeException();
                }
            }

            Elements.Add(element);
        }
    }

    public List<BioStateEventElement> Elements { get; set; }

    public int Id { get; set; }
}

public abstract class BioStateEventElement : BioVersionedNativeObject
{
    protected BioStateEventElement(BinaryReader reader)
        : base(reader)
    {
        InstanceVersion = reader.ReadInt32();
    }

    public abstract StateEventElementType ElementType { get; }
}

public class BioStateEventElementBool : BioStateEventElement
{
    public BioStateEventElementBool(BinaryReader reader)
        : base(reader)
    {
        GlobalBool = reader.ReadInt32();
        NewState = Convert.ToBoolean(reader.ReadInt32());
        UseParam = Convert.ToBoolean(reader.ReadInt32());
    }

    public int GlobalBool { get; set; }

    public bool NewState { get; set; }

    public bool UseParam { get; set; }

    #region Overrides of BioStateEventElement

    public override StateEventElementType ElementType
    {
        get { return StateEventElementType.Bool; }
    }

    #endregion
}

public class BioStateEventElementConsequence : BioStateEventElement
{
    public BioStateEventElementConsequence(BinaryReader reader)
        : base(reader)
    {
        Consequence = reader.ReadInt32();
    }

    public int Consequence { get; set; }

    #region Overrides of BioStateEventElement

    public override StateEventElementType ElementType
    {
        get { return StateEventElementType.Consequence; }
    }

    #endregion
}

public class BioStateEventElementFloat : BioStateEventElement
{
    public BioStateEventElementFloat(BinaryReader reader)
        : base(reader)
    {
        GlobalFloat = reader.ReadInt32();
        NewValue = reader.ReadSingle();
        UseParam = Convert.ToBoolean(reader.ReadInt32());
        Increment = Convert.ToBoolean(reader.ReadInt32());
    }

    public int GlobalFloat { get; set; }

    public float NewValue { get; set; }

    public bool UseParam { get; set; }

    public bool Increment { get; set; }

    #region Overrides of BioStateEventElement

    public override StateEventElementType ElementType
    {
        get { return StateEventElementType.Float; }
    }

    #endregion
}

public class BioStateEventElementFunction : BioStateEventElement
{
    public BioStateEventElementFunction(BinaryReader reader)
        : base(reader)
    {
        FunctionPackage = reader.ReadInt64();
        FunctionClass = reader.ReadInt64();
        FunctionName = reader.ReadInt64();
        Parameter = reader.ReadInt32();
    }

    public UName FunctionPackage { get; set; }

    public UName FunctionClass { get; set; }

    public UName FunctionName { get; set; }

    public int Parameter { get; set; }

    #region Overrides of BioStateEventElement

    public override StateEventElementType ElementType
    {
        get { return StateEventElementType.Function; }
    }

    #endregion
}

public class BioStateEventElementInt : BioStateEventElement
{
    public BioStateEventElementInt(BinaryReader reader)
        : base(reader)
    {
        GlobalInt = reader.ReadInt32();
        NewValue = reader.ReadInt32();
        UseParam = Convert.ToBoolean(reader.ReadInt32());
        Increment = Convert.ToBoolean(reader.ReadInt32());
    }

    public int GlobalInt { get; set; }

    public int NewValue { get; set; }

    public bool UseParam { get; set; }

    public bool Increment { get; set; }

    #region Overrides of BioStateEventElement

    public override StateEventElementType ElementType
    {
        get { return StateEventElementType.Int; }
    }

    #endregion
}

public abstract class BioStateEventElementLocal : BioStateEventElement
{
    protected BioStateEventElementLocal(BinaryReader reader)
        : base(reader)
    {
        ObjectTag = reader.ReadInt64();
        FunctionName = reader.ReadInt64();
        ObjectType = reader.ReadInt32();
        UseParam = Convert.ToBoolean(reader.ReadInt32());
    }

    public UName ObjectTag { get; set; }

    public UName FunctionName { get; set; }

    public int ObjectType { get; set; }

    public bool UseParam { get; set; }
}

public class BioStateEventElementLocalBool : BioStateEventElementLocal
{
    public BioStateEventElementLocalBool(BinaryReader reader)
        : base(reader)
    {
        NewValue = Convert.ToBoolean(reader.ReadInt32());
    }

    public bool NewValue { get; set; }

    #region Overrides of BioStateEventElement

    public override StateEventElementType ElementType
    {
        get { return StateEventElementType.LocalBool; }
    }

    #endregion
}

public class BioStateEventElementLocalFloat : BioStateEventElementLocal
{
    public BioStateEventElementLocalFloat(BinaryReader reader)
        : base(reader)
    {
        NewValue = reader.ReadSingle();
    }

    public float NewValue { get; set; }

    #region Overrides of BioStateEventElement

    public override StateEventElementType ElementType
    {
        get { return StateEventElementType.LocalFloat; }
    }

    #endregion
}

public class BioStateEventElementLocalInt : BioStateEventElementLocal
{
    public BioStateEventElementLocalInt(BinaryReader reader)
        : base(reader)
    {
        NewValue = reader.ReadInt32();
    }

    public int NewValue { get; set; }

    #region Overrides of BioStateEventElement

    public override StateEventElementType ElementType
    {
        get { return StateEventElementType.LocalInt; }
    }

    #endregion
}

public class BioStateEventElementSubstate : BioStateEventElement
{
    public BioStateEventElementSubstate(BinaryReader reader)
        : base(reader)
    {
        GlobalBool = reader.ReadInt32();
        ParentIndex = reader.ReadInt32();
        NewState = Convert.ToBoolean(reader.ReadInt32());
        UseParam = Convert.ToBoolean(reader.ReadInt32());
        ParentTypeOr = Convert.ToBoolean(reader.ReadInt32());

        var siblingIndicesCount = reader.ReadInt32();
        SiblingIndices = new List<int>();

        for (var i = 0; i < siblingIndicesCount; i++)
        {
            SiblingIndices.Add(reader.ReadInt32());
        }
    }

    public List<int> SiblingIndices { get; set; }

    public int GlobalBool { get; set; }

    public int ParentIndex { get; set; }

    public bool NewState { get; set; }

    public bool UseParam { get; set; }

    public bool ParentTypeOr { get; set; }

    #region Overrides of BioStateEventElement

    public override StateEventElementType ElementType
    {
        get { return StateEventElementType.Substate; }
    }

    #endregion
}


Unreal Engine shared types:
Code: Select all
public class UName
{
    public UName(string value = "None", int index = 0, int flags = 0)
    {
        Flags = flags;
        Index = index;
        Value = value;
    }

    public int Flags { get; set; }

    public int Index { get; set; }

    public string Value { get; set; }

    public static implicit operator UName(string value)
    {
        return new UName(value);
    }

    public static implicit operator UName(int value)
    {
        return new UName(index: value);
    }

    public static implicit operator UName(long value)
    {
        int index, flags;
        value.Split(out index, out flags);

        return new UName(index: index, flags: flags);
    }

    public static implicit operator int(UName name)
    {
        return name.Index;
    }

    public static implicit operator long(UName name)
    {
        return name.Index.Join(name.Flags);
    }

    public static implicit operator string(UName name)
    {
        return name.Value;
    }
}

public struct UPointer
{
    public UPointer(int dummy = 0)
        : this()
    {
        Dummy = dummy;
    }

    public int Dummy { get; set; }

    public static implicit operator UPointer(int i)
    {
        return new UPointer(i);
    }

    public static implicit operator int(UPointer pointer)
    {
        return pointer.Dummy;
    }
}

public struct UStringRef
{
    public UStringRef(int index = 0, string value = "None")
        : this()
    {
        Index = index;
        Value = value;
    }

    public int Index { get; set; }

    public string Value { get; set; }

    public static implicit operator UStringRef(string value)
    {
        return new UStringRef(value: value);
    }

    public static implicit operator UStringRef(int value)
    {
        return new UStringRef(value);
    }

    public static implicit operator int(UStringRef stringRef)
    {
        return stringRef.Index;
    }

    public static implicit operator string(UStringRef stringRef)
    {
        return stringRef.Value;
    }
}


Extensions:
Code: Select all
public static class BinaryReaderExtensions
{
    public static long Seek(this BinaryReader reader, long offset, SeekOrigin origin = SeekOrigin.Begin)
    {
        return reader.BaseStream.Seek(offset, origin);
    }
}
   
public static class Int32Extensions
{
    public static long Join(this int i, int i2)
    {
        long b = i2;
        b = b << 32;
        b = b | (uint)i;

        return b;
    }
}

public static class Int64Extensions
{
    public static void Split(this long l, out int i1, out int i2)
    {
        i1 = (int)(l & uint.MaxValue);
        i2 = (int)(l >> 32);
    }
}


These are the mostly the same between Mass Effect 2 & 3, with some possible slight differences based on the nInstanceVersion. Also, one reason I ended up doing this was because in ME3, Tali's dialogue does not reset post-mission. Reason being, they called for the wrong state transition, which does not exist.

If there are any issues, let me know, I may have made one or more while typing this up and copying from my code to this. Hope this helps with codex, quest or state event editing.
Last edited by TankMaster on 26 May 2014, 01:52, edited 2 times in total.
TankMaster
User
 
Posts: 173
Joined: 02 Nov 2012, 01:19
Location: Indiana
Has thanked: 6 time
Have thanks: 64 time

Re: Done Research: Plot Manager Native Objects

Postby WarrantyVoider » 22 May 2014, 20:36

there are tools for this, codex editor and questmap editor, also propertydumper and propertydb, which will determine all possibly used properties of a given class, propertydb does this for all classes. btw, if you can code, why arent you on our team yet?! :P

greezt WV

PS:check pm
always backup your files!
mess with the best or die like the rest!
"I tried everything!" - "mkay, please list that..." ; please dont pm me for help, we have a help section
User avatar
WarrantyVoider
Emeritus
 
Posts: 2270
Joined: 22 Aug 2012, 11:33
Has thanked: 480 time
Have thanks: 626 time

Re: Done Research: Plot Manager Native Objects

Postby TankMaster » 22 May 2014, 20:48

Lol, yeah prob should. I just figured I would add this as when I view the latest code that the Codex & Quest editors did not have nor display this. I could easily be wrong on that one though.
TankMaster
User
 
Posts: 173
Joined: 02 Nov 2012, 01:19
Location: Indiana
Has thanked: 6 time
Have thanks: 64 time

Re: Done Research: Plot Manager Native Objects

Postby giftfish » 22 May 2014, 21:45

Well, taking a very quick look at this it looks interesting. I think there are things here that the codex editor is missing and that might very well explain a could things I can get to work when adding new codex entries.

I'll try to take a better look in a bit :)
giftfish
 

Re: Done Research: Plot Manager Native Objects

Postby giftfish » 24 May 2014, 17:48

I'm one of the few people who has used the Codex Editor, so I have a couple questions on what you've found here. Thanks, btw :)

Code: Select all
BioCodexMap:
Code:
struct BioCodexEntry : BioVersionedNativeObject
    int Id
    // InstanceVersion
    int Title
    int Description
    int TextureIndex
    int Priority
    int CodexSound // If InstanceVersion is 4 or higher, otherwise it is not present

struct BioCodexPage : BioCodexEntry
    int Section

struct BioCodexSection : BioCodexEntry
    int IsPrimary // bool

class BioCodexMap
    int SectionsCount
    Dictionary<int, BioCodexSection> Sections
   
    int PagesCount
    Dictionary<int, BioCodexPage> Pages

Here's my tutorial on deciphering the contents of the Codex Editor that's currently in place and how to edit it and create a new entry.

If you look toward the beginning, you'll see that I provide an explanation of what the different numbers/variables mean, positions 1 thru 11, I call them. I'd appreciate if you took a look at this, and try to relate your names to mine, that way I can replace them with the proper terminology.

In addition, there are two things I'm wondering about. Well, 3 actually:

1. "int TextureIndex"
As far as I can tell, this is nowhere in the current editor, and this seems like it could be linked to the problem I have with a game crash/freeze when viewing a newly added primary codex entry with custom texture. We've re-purposed a Kinect Game Manual texture and linked it to the new entry in the nID list in the coalesced, but many of our mod users get a game crash when they view it in game. The texture is there, and according to ProcMon, the file containing the texture is the last one loaded before the crash.

In other words, if there is supposed to be a parameter in the Codex Editor that relates to textures, then it's probably not there and as a result, I haven't edited it.

2. "// InstanceVersion" (what is "//", btw?) and "int CodexSound // If InstanceVersion is 4 or higher, otherwise it is not present"
I'm wondering if one of these is position 5 in the Codex Editor? What's strange is that every entry has "4" in this location, and that includes the secondary codex entries that are not narrated. I left this as 4 for our new entry, which is a primary entry that theoretically should have narration, but does not. So, if the game is looking for a sound file and can't find it, it could be that it's causing a crash/freeze. Would I maybe need to change this to 0-3?

3. Entries present at the beginning of the game.
If you take a look at this post, you'll see I'm trying to add two secondary entries to ME3 that should simply be base entries. Present at the start of the game without "triggering." So far, I've been unable to get this to work. If you have any thoughts, based upon your work on this stuff, I'd be very interested to hear it.

Oops, and a final question. Do have any idea why the integers in position 10 are negative, when they are not equal to zero?
giftfish
 

Re: Done Research: Plot Manager Native Objects

Postby giftfish » 24 May 2014, 18:11

Just starting to try to "align" my list with yours. I think these are all the variables you found:

As I state above, there are "11 positions" in the current editor. That includes an offset (I think; I'm not a coder), a row number (not sure if that counts for any of these below), and a "separator" (a semicolon).

For example:
Code: Select all
96 @0x0000C14 : 5333 4  340863 340862 28 3 0 7189

int ID >> nID? (position 8) or possibly position 5?
//instance version >> position 5?
int Title >> Probably the title in tlk, position 6
int Descriptions >> Probably description in tlk, position 7
int Texture Index >> nID (position 8?)
int Priority >> possibly the "sorting" number, which is position 9?
int Codex Sound // If InstanceVersion is 4 or higher, otherwise it is not present >> ?
int Section >> possibly position 11?
int IsPrimary //bool >> If you mean this is the bool, then that's position 4
Int SectionsCount >> ?
Int PagesCount >> position 10?

Lots are questionable and I'm totally missing two or three, all of which would correspond to the first 3 positions above that don't seem to be a part of the the list.
giftfish
 

Re: Done Research: Plot Manager Native Objects

Postby TankMaster » 25 May 2014, 18:37

Ah yeah, the // is just where I put in a comment.

The ID value has 2 purposes in this case, it is the id of the codex entry (section or page) and it is also used as the key part of the key-value pair (value being the actual entry). So in the data it is stored:

Id (4 bytes)
InstanceVersion (4 bytes)
Title (4 bytes)
Description (4 bytes)
TextureIndex (4 bytes)
Priority (4 bytes)


CodexSound only exists if the InstanceVersion is 4. Mass Effect 2 is slightly different, at least in the case of the primary codex map, InstanceVersion is 2 in that case. Title & Description are string references that are entries inside the .tlk files.

The sections and pages array are split inside the binary data, sections then pages, so you have:
SectionsCount, Sections, PagesCount, Pages

So sections have the variables:
Id, InstanceVersion, Title, Description, TextureIndex, Priority, CodexSound, IsPrimary

Pages have:
Id, InstanceVersion, Title, Description, TextureIndex, Priority, CodexSound, Section

Example:
Ignore the numbers before the : in the codex editor, they aren't values.

First entry that shows up in codex editor is:
13385 4 331771 -1 0 3 0 1

Id = 13385
InstanceVersion = 4
Title = 331771
Description = -1 (which means it doesn't have a description)
TextureIndex = 0
Priority = 3
CodexSound = 0
IsPrimary = 1


If this was a page, the last value would be SectionId instead of IsPrimary.

To show the difference for Mass Effect 2, lets say it has the same values but InstanceVersion would be 2 instead of 4.
Id = 13385
InstanceVersion = 2
Title = 331771
Description = -1
TextureIndex = 0
Priority = 3
IsPrimary = 1


As for the example you posted, this is a page entry:
5333 4  340863 340862 28 3 0 7189

Id = 5333
InstanceVersion = 4
Title = 340863
Description = 340862
TextureIndex = 28
Priority = 3
CodexSound = 0
SectionId = 7189


Hope this helps, I'm not the best when it comes to explaining these things lol.

Edit:
I noticed a bug in my code with the codex map, it was only looping through the pages by the same amount it does for sections. As such, CodexSound can be positive or negative values. Negative means it is pulling it from the pcc's import table. Positive means it is pulling it from the pcc's export table (or so it appears to be the case).
Last edited by TankMaster on 26 May 2014, 02:00, edited 6 times in total.
TankMaster
User
 
Posts: 173
Joined: 02 Nov 2012, 01:19
Location: Indiana
Has thanked: 6 time
Have thanks: 64 time

Re: Done Research: Plot Manager Native Objects

Postby TankMaster » 25 May 2014, 19:07

Also, I had planned to release the modified Codex & Quest editor, just haven't gotten around to finishing the editing features of it, lol. I also will release the State Transition editor.
TankMaster
User
 
Posts: 173
Joined: 02 Nov 2012, 01:19
Location: Indiana
Has thanked: 6 time
Have thanks: 64 time

Re: Done Research: Plot Manager Native Objects

Postby giftfish » 26 May 2014, 16:12

Ok, some of this was a bit confusing at first, but I think I'm getting it. I still have a few questions, though, and a couple comments.


1. Sections versus Pages. What do these mean as far as viewing the codex in game? If codex entry 0 in the editor is a "section," string 331771 leads to "Aliens: Council Races." So, these would all be what I might call "category headers" in the codex, yes? So, a "page" is an actual "entry," so to speak?

2. "(Plot)ID." This is definitely the plot bool associated with the entry. "ID" seems to be short for "PlotStateID." Therefore, I'm confused about your notation in the OP associating "bool" with "Is Primary."

3. "IsPrimary" -- This value can be 0 or 1 for "sections," as you say. The obvious meaning for this parameter this that the entry is associated with the primary codex. But one I just looked up "Aliens: Extinct Races" has a 0 in this location, but has both primary and secondary entries. Thoughts?

4. "nID/Texture Index". Coalesced.bin has a list at this location: bioui.ini > sfxgame > sfxgui > journalcodex > lstimages. It uses the "nID" for each primary entry and links it to an image. I thought "nID" would be the same as your "ID" but it doesn't seem to be (see above). What it seems to be is the "Texture Index." Any idea why some of these would have a -1 value? For example, all secondary codex entries have a value of 0 here, as they all use the same image as defined in the Coalesced.bin.

5. Description. It seems like both 0 and -1 can mean no description. Any idea why?

6. InstanceVersion. What does this mean? Every single entry in the editor has 4 in this location, and that includes secondary entries without sound. Is this an error in the current editor?

7. Priority. This one makes sense. It's what I call the "sorting order" and determines how the entries/pages order themselves when displayed in game. A 3 is "standard."

8. Codex Sound. This is where it gets interesting. Ok, so the +/- indicates the file location that is being read. Which means, if there is no sound this should be zero. This also lines up with my previous explanation as far as every primary entry/page having a unique number here, and that's because even for folks like Anderson, the texture ID will be the same, but the TLK strings and VO narration have to be different. The first thing I'm going to try then, is changing this to 0 to see if it fixes our crash issue. What I don't know is if the InstanceVersion should be changed or not. (EDIT: It doesn't, see posts below).

9. Section ID. This is what determines where the entry/page appears. So, it links it to a "section," I guess is how to think about it. The deceiving thing is that just because a number is here doesn't mean the entry actually appears in the codex, which is something I discuss in the tutorial.

-----------------------------
And, finally, any idea about the entries that are present at the start of the game? The two I want to add are always in the editor, but they were linked to an ME2 SectionID and not and ME3 one. So, I found the proper ID and inserted it and then added the relevant plotboolIDs to the list in the Coalesced (the newgamestartingentries list). Yet, they still don't appear at the start of the game. The only way I can get them to appear is by linking them to bools that pop during the course of the game, and then only one entry will pop per bool. Are you saying I should try an instance version of 2? I will, but I just want to make sure I'm understanding you correctly :)

Once I'm clear, then I can update the tutorial...again, lol.

Thanks!
giftfish
 

Re: Done Research: Plot Manager Native Objects

Postby giftfish » 27 May 2014, 15:07

Progress!

If I set the CodexSound parameter to 0 for the entry that was giving us a crash/freeze, then it no longer crashes/freezes! :D I still need to get a couple other folks to test for me, but that mystery might finally be solved.

As for the secondary entries I'm trying to place into the codex at the beginning of the game, I tried changing the IV to 2 from 4 and the game hung with an infinite loading screen when I tried loading a save on Vancouver. So, that certainly seemed to do something. Going to try one other idea with that...
giftfish
 

Next

Return to Technical Research

Who is online

Users browsing this forum: No registered users and 0 guests

cron
suspicion-preferred