Skip to content

Commit

Permalink
Merge pull request #98 from FWDekker/modernise
Browse files Browse the repository at this point in the history
Significantly improve performance, ignore PLYT records, add version detection, improve code style
  • Loading branch information
FWDekker authored Oct 16, 2024
2 parents 5aec221 + f21571d commit decc81f
Show file tree
Hide file tree
Showing 34 changed files with 1,033 additions and 1,204 deletions.
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog
## Unreleased
## [4.0.1] -- 2023-10-16
No changes have been made to the output format or contents.

* Automatically detect game version number from executable.
* Explicitly ignore `PLYT` records to prevent crash with EcksEdit 4.1.6.9 on latest PTS versions.
* Significantly speed up dump scripts (from 5 hours to 2 hours) by reducing "multiplexer" complexity and inlining utility functions.
* Modernise Python project dependency management.
* Format all Python code using [Black](https://black.readthedocs.io/en/stable/).
* Re-format all Pascal code using [updated project code style](https://github.com/FWDekker/fo76-dumps/wiki/Code-style).


## [4.0.0] -- 2023-10-13
Expand Down
310 changes: 105 additions & 205 deletions Edit scripts/ExportAll.pas

Large diffs are not rendered by default.

135 changes: 1 addition & 134 deletions Edit scripts/ExportCore.pas
Original file line number Diff line number Diff line change
Expand Up @@ -7,135 +7,10 @@

(***
*
* Shorthands for commonly used functions.
*
* Some terminology: Given an element identified as `EDID - Editor ID`, the signature is `EDID` and the name is
* `EDID - Editor ID`. If an element has no signature, it can only be addressed by its name. A nested element can be
* addressed by its path, which is a sequence of signatures and names (or mixtures thereof), separated by backslashes.
* xEdit utility functions
*
**)

(**
* Shorthand for [getEditValue].
*)
function gev(el: IwbElement): String;
begin
result := getEditValue(el);
end;

(**
* Shorthand for [elementBySignature].
*)
function eBySign(el: IwbContainer; sig: String): IwbElement;
begin
result := elementBySignature(el, sig);
end;

(**
* Shorthand for [elementByName].
*)
function eByName(el: IwbContainer; nam: String): IwbElement;
begin
result := elementByName(el, nam);
end;

(**
* Shorthand for [elementByPath].
*)
function eByPath(el: IwbContainer; path: String): IwbElement;
begin
result := elementByPath(el, path);
end;

(**
* Shorthand for [elementExists].
*)
function eHasByPath(el: IwbContainer; path: String): Boolean;
begin
result := elementExists(el, path);
end;

(**
* Shorthand for [elementCount].
*)
function eCount(el: IwbContainer): Integer;
begin
result := elementCount(el);
end;

(**
* Shorthand for [elementByIndex].
*)
function eByIndex(el: IwbContainer; i: Integer): IwbElement;
begin
result := elementByIndex(el, i);
end;

(**
* Shorthand for calling [getEditValue] and [elementBySignature].
*)
function evBySign(el: IInterface; sig: String): String;
begin
result := gev(eBySign(el, sig));
end;

(**
* Shorthand for calling [getEditValue] and [elementByName].
*)
function evByName(el: IInterface; nam: String): String;
begin
result := gev(eByName(el, nam));
end;

(**
* Shorthand for calling [getEditValue] and [elementByPath].
*)
function evByPath(el: IInterface; path: String): String;
begin
result := gev(eByPath(el, path));
end;

(**
* Shorthand for calling [getEditValue] and [elementByIndex].
*)
function evByIndex(el: IInterface; i: Integer): String;
begin
result := gev(eByIndex(el, i));
end;

(**
* Shorthand for calling [linksTo] and [elementBySignature].
*)
function linkBySign(el: IInterface; sig: String): IInterface;
begin
result := linksTo(eBySign(el, sig));
end;

(**
* Shorthand for calling [linksTo] and [elementByName].
*)
function linkByName(el: IInterface; nam: String): IInterface;
begin
result := linksTo(eByName(el, nam));
end;

(**
* Shorthand for calling [linksTo] and [elementByPath].
*)
function linkByPath(el: IInterface; path: String): IInterface;
begin
result := linksTo(eByPath(el, path));
end;

(**
* Shorthand for calling [linksTo] and [elementByIndex].
*)
function linkByIndex(el: IInterface; i: Integer): IInterface;
begin
result := linksTo(eByIndex(el, i));
end;


(**
* Returns a lowercase string representation of [el]'s form ID.
*
Expand All @@ -147,14 +22,6 @@ function stringFormID(el: IInterface): String;
result := lowerCase(intToHex(formID(el), 8));
end;



(***
*
* xEdit utility functions
*
**)

(**
* Returns `true` iff [el] is referenced by a record with signature [sig].
*
Expand Down
24 changes: 12 additions & 12 deletions Edit scripts/ExportJson.pas
Original file line number Diff line number Diff line change
Expand Up @@ -92,22 +92,22 @@ function getJsonPropertyObject(el: IInterface): String;
begin
result := '';

props := eBySign(el, 'PRPS');
for i := 0 to eCount(props) - 1 do begin
prop := eByIndex(props, i);
avEdid := evBySign(linkByName(prop, 'Actor Value'), 'EDID');
props := elementBySignature(el, 'PRPS');
for i := 0 to elementCount(props) - 1 do begin
prop := elementByIndex(props, i);
avEdid := getEditValue(elementBySignature(linksTo(elementByName(prop, 'Actor Value')), 'EDID'));

if assigned(linkByName(prop, 'Curve Table')) then begin
avValue := evBySign(linkByName(prop, 'Curve Table'), 'EDID');
if assigned(linksTo(elementByName(prop, 'Curve Table'))) then begin
avValue := getEditValue(elementBySignature(linksTo(elementByName(prop, 'Curve Table')), 'EDID'));
end else begin
avValue := evByName(prop, 'Value');
avValue := getEditValue(elementByName(prop, 'Value'));
end;
try
avValue := floatToStr(strToFloat(avValue)); // Remove unnecessary decimals
except end;

result := result + '"' + escapeJson(avEdid) + '":"' + escapeJson(avValue) + '"';
if i < eCount(props) - 1 then begin
if i < elementCount(props) - 1 then begin
result := result + ',';
end;
end;
Expand All @@ -129,8 +129,8 @@ function getJsonChildArray(list: IInterface): String;
begin
resultList := TStringList.create();

for i := 0 to eCount(list) - 1 do begin
resultList.add(evByIndex(list, i));
for i := 0 to elementCount(list) - 1 do begin
resultList.add(getEditValue(elementByIndex(list, i)));
end;

resultList.sort();
Expand All @@ -152,8 +152,8 @@ function getJsonChildNameArray(list: IInterface): String;
begin
resultList := TStringList.create();

for i := 0 to eCount(list) - 1 do begin
resultList.add(name(eByIndex(list, i)));
for i := 0 to elementCount(list) - 1 do begin
resultList.add(name(elementByIndex(list, i)));
end;

resultList.sort();
Expand Down
103 changes: 50 additions & 53 deletions Edit scripts/ExportTabularALCH.pas
Original file line number Diff line number Diff line change
Expand Up @@ -12,55 +12,52 @@ function initialize(): Integer;
begin
ExportTabularALCH_outputLines := TStringList.create();
ExportTabularALCH_outputLines.add(
'"File"' // Name of the originating ESM
+ ', "Form ID"' // Form ID
+ ', "Editor ID"' // Editor ID
+ ', "Name"' // Full name
+ ', "Description"' // Description
+ ', "Weight"' // Weight
+ ', "Value"' // Value
+ ', "Flags"' // Sorted list of flag names
+ ', "Addiction"' // Editor ID of addiction (possibly null)
+ ', "Addiction chance"' // Addiction chance
+ ', "Health"' // Editor ID of health curve table (possibly null)
+ ', "Spoiled"' // Editor ID of spoiled version (possibly null)
+ ', "Effects"' // Unsorted array of effect objects. Conditions are not included
+ ', "Keywords"' // Sorted JSON array of keywords. Each keyword is represented as
'"File", ' + // Name of the originating ESM
'"Form ID", ' + // Form ID
'"Editor ID", ' + // Editor ID
'"Name", ' + // Full name
'"Description", ' + // Description
'"Weight", ' + // Weight
'"Value", ' + // Value
'"Flags", ' + // Sorted list of flag names
'"Addiction", ' + // Editor ID of addiction (possibly null)
'"Addiction chance", ' + // Addiction chance
'"Health", ' + // Editor ID of health curve table (possibly null)
'"Spoiled", ' + // Editor ID of spoiled version (possibly null)
'"Effects", ' + // Unsorted array of effect objects. Conditions are not included
'"Keywords"' // Sorted JSON array of keywords. Each keyword is represented as
// `{EditorID} [KYWD:{FormID}]`
);
end;

function canProcess(el: IInterface): Boolean;
function process(el: IInterface): Integer;
begin
result := signature(el) = 'ALCH';
if signature(el) <> 'ALCH' then begin exit; end;

_process(el);
end;

function process(alch: IInterface): Integer;
function _process(alch: IInterface): Integer;
var enit: IInterface;
outputString: String;
begin
if not canProcess(alch) then begin
addWarning(name(alch) + ' is not a ALCH. Entry was ignored.');
exit;
end;

enit := eBySign(alch, 'ENIT');
enit := elementBySignature(alch, 'ENIT');

outputString :=
escapeCsvString(getFileName(getFile(alch))) + ', '
+ escapeCsvString(stringFormID(alch)) + ', '
+ escapeCsvString(evBySign(alch, 'EDID')) + ', '
+ escapeCsvString(evBySign(alch, 'FULL')) + ', '
+ escapeCsvString(evBySign(alch, 'DESC')) + ', '
+ escapeCsvString(evBySign(alch, 'DATA')) + ', '
+ escapeCsvString(evByName(enit, 'Value')) + ', '
+ escapeCsvString(getJsonFlagArray(eByName(enit, 'Flags'))) + ', '
+ escapeCsvString(evByName(enit, 'Addiction')) + ', '
+ escapeCsvString(evByName(enit, 'Addiction Chance')) + ', '
+ escapeCsvString(evByName(enit, 'Health')) + ', '
+ escapeCsvString(evByName(enit, 'Spoiled')) + ', '
+ escapeCsvString(getJsonEffectsArray(eByName(alch, 'Effects'))) + ', '
+ escapeCsvString(getJsonChildArray(eByPath(alch, 'Keywords\KWDA')));
escapeCsvString(getFileName(getFile(alch))) + ', ' +
escapeCsvString(stringFormID(alch)) + ', ' +
escapeCsvString(getEditValue(elementBySignature(alch, 'EDID'))) + ', ' +
escapeCsvString(getEditValue(elementBySignature(alch, 'FULL'))) + ', ' +
escapeCsvString(getEditValue(elementBySignature(alch, 'DESC'))) + ', ' +
escapeCsvString(getEditValue(elementBySignature(alch, 'DATA'))) + ', ' +
escapeCsvString(getEditValue(elementByName(enit, 'Value'))) + ', ' +
escapeCsvString(getJsonFlagArray(elementByName(enit, 'Flags'))) + ', ' +
escapeCsvString(getEditValue(elementByName(enit, 'Addiction'))) + ', ' +
escapeCsvString(getEditValue(elementByName(enit, 'Addiction Chance'))) + ', ' +
escapeCsvString(getEditValue(elementByName(enit, 'Health'))) + ', ' +
escapeCsvString(getEditValue(elementByName(enit, 'Spoiled'))) + ', ' +
escapeCsvString(getJsonEffectsArray(elementByName(alch, 'Effects'))) + ', ' +
escapeCsvString(getJsonChildArray(elementByPath(alch, 'Keywords\KWDA')));

ExportTabularALCH_outputLines.add(outputString);
end;
Expand Down Expand Up @@ -124,33 +121,33 @@ function getJsonEffectsArray(effects: IInterface): String;

resultList := TStringList.create();

for i := 0 to eCount(effects) - 1 do begin
effect := eByIndex(effects, i);
efit := eBySign(effect, 'EFIT');
for i := 0 to elementCount(effects) - 1 do begin
effect := elementByIndex(effects, i);
efit := elementBySignature(effect, 'EFIT');

if eHasByPath(effect, 'MAGG - Magnitude') then begin
magnitude := evBySign(effect, 'MAGG');
end else if eHasByPath(efit, 'Magnitude') then begin
magnitude := evByName(efit, 'Magnitude');
if elementExists(effect, 'MAGG - Magnitude') then begin
magnitude := getEditValue(elementBySignature(effect, 'MAGG'));
end else if elementExists(efit, 'Magnitude') then begin
magnitude := getEditValue(elementByName(efit, 'Magnitude'));
end else begin
magnitude := '';
end;

if eHasByPath(effect, 'DURG - Duration') then begin
duration := evBySign(effect, 'DURG');
end else if eHasByPath(efit, 'Duration') then begin
duration := evByName(efit, 'Duration');
if elementExists(effect, 'DURG - Duration') then begin
duration := getEditValue(elementBySignature(effect, 'DURG'));
end else if elementExists(efit, 'Duration') then begin
duration := getEditValue(elementByName(efit, 'Duration'));
end else begin
duration := '';
end;

resultList.add(
'{' +
'"Base Effect":"' + escapeJson(evBySign(effect, 'EFID')) + '"' +
',"Magnitude":"' + escapeJson(magnitude) + '"' +
',"Duration":"' + escapeJson(duration) + '"' +
',"Area":"' + escapeJson(evByName(efit, 'Area')) + '"' +
',"Curve Table":"' + escapeJson(evBySign(effect, 'CVT0')) + '"' +
'"Base Effect":"' + escapeJson(getEditValue(elementBySignature(effect, 'EFID'))) + '",' +
'"Magnitude":"' + escapeJson(magnitude) + '",' +
'"Duration":"' + escapeJson(duration) + '",' +
'"Area":"' + escapeJson(getEditValue(elementByName(efit, 'Area'))) + '",' +
'"Curve Table":"' + escapeJson(getEditValue(elementBySignature(effect, 'CVT0'))) + '"' +
'}'
);
end;
Expand Down
Loading

0 comments on commit decc81f

Please sign in to comment.