MadTekN1 / ERModsMerger

Simple little tool to merge Elden Ring mods
MIT License
19 stars 2 forks source link

Add support for TAEs #2

Open davidrogers090 opened 3 months ago

davidrogers090 commented 3 months ago

It would be very helpful if ERModsMerger could merge TAEs. It could read the TAE files in each mod and find how they differ from vanilla. First step would be to merge files with no conflicts. That is, whole aXX.tae files where the other mod does not have a corresponding aXX.tae.

Then it could read within the conflicting TAE files and do the following depending on the situation:

Mod 1 Mod 2 Vanilla Result
N/A N/A N/A Nothing to do
N/A N/A a000_012345 Use vanilla
N/A a000_012345 N/A Use mod 2
N/A a000_012345 a000_012345 Use mod 2
a000_012345 N/A N/A Use mod 1
a000_012345 N/A a000_012345 Use mod 1
a000_012345 a000_012345 N/A Change ID of one of them?
a000_012345 a000_012345 a000_012345 Prompt for manual resolution?

I am willing to help implement this.

MadTekN1 commented 3 months ago

Thanks for your interest on this tool :)

I don't know yet what is the structure inside TAE files.

First step would be to merge files with no conflicts

This is already done, as the first step and by default the tool copy to output directory all the mod files.

Then finding conflicting files is also done too. If you want to understand quickly how the merger work I suggest you to read the small CodeDoc I wrote to help people who want to contribute.

Long story short, I tried as much as possible easy add new merging classes in code, every conflicting files are distributed through MergeableFilesDispatcher class, to add new merging class, just add a new one and try to use the same pattern as classes inside ERModsMerger.Core/Formats and then call the function from the dispatcher just by adding a case inside MergeableFilesDispatcher.MergeAllConflicts(bool manualConflictsResolving) function like this

public void MergeAllConflicts(bool manualConflictsResolving)
{
    foreach (var conflict in Conflicts)
    {
        switch(conflict.FilesToMerge[0].ModRelativePath)
        {
            case string a when a.Contains("regulation.bin"): RegulationBin.MergeRegulationsV2(conflict.FilesToMerge, manualConflictsResolving); break;
            case string a when a.Contains(".emevd.dcx"): EMEVD_DCX.MergeFiles(conflict.FilesToMerge); break; //WIP //to be tested
            case string a when a.Contains(".msgbnd.dcx"): MSGBND_DCX.MergeFiles(conflict.FilesToMerge); break; //WIP //to be tested
            case string a when a.Contains(".hks"): LUA_HKS.MergeFiles(conflict.FilesToMerge); break; //WIP //to be tested

            case string a when a.Contains(".tae"): TAE_EXAMPLE.MergeFiles(conflict.FilesToMerge); break; // JUST AN EXAMPLE
        }
    }
}

I have some IRL professional obligations that I can't avoid and won't be able to progress on this during next week, but I'm still trying to stay active on Nexus, Discord and GitHub.

If you want to talk more easily about code, maybe join the Discord

Also, even if all this is a passion project and is not for profits, I'm willing to share with contributors, Nexus rewards program DP points and direct donations community might give. My main focus on this (as my first open source project) is to better understand ER modding but also bring to community a real good tool for managing and merging mods to keep this awesome game alive as long as possible and even why not make this a standard. Seeing you as the potential really first contributor on this make me believe this goal is achievable :)

davidrogers090 commented 3 months ago

Hmm, so the .taes seem to reference .hkx files in other bundles. To merge these .hkx files I imagine we would have to resolve conflicts by renaming some of these files. We would have to track what we rename and pass that to the tae merger so that it can update the references as it goes. That means we would have to merge the .hkx files first and the tae bundles after. That might require an architecture change. Thoughts?

MadTekN1 commented 3 months ago

I don't really know about tae and hkx but I was thinking the same for move set merging, as Lua scripts references files and params (SpEffect for example). Having objects to store references and use the ref list to merger classes would be great.

If you think an architecture change is needed, yes why not we can do that :)

If we have to deal with tons of references in multiple files maybe the best would be to split the process in multiple passes:

  1. Gather modifications (mods diff compared to vanilla), pretty like the reg bin merge in public List<ParamRowToMerge> FindRowsToMerge(Dictionary<string, PARAM> vanillaParams) but for all files first
  2. Search and store references
  3. Create new or update direct conflicting references if any
  4. Finally, for all modifications => load vanilla base files => Apply modifs & refs => Write files to output dir

Still, in my opinion, the best is to make this thing work for most case scenarios at first, if we have very hard conflicting things to solve but rarely encountered in mods, we can move on and figure it out later.