Support Near reference, proper same cell detection

This commit is contained in:
Eddoursul 2022-10-10 20:54:53 +02:00
parent 7378a8de90
commit 718cf89351

View File

@ -16,7 +16,7 @@ unit ESMify_Plugins;
var
refsChecked, recordsCounted, flaggedCount, persLocSkipped: integer;
pluginAnnounced: boolean;
pluginShown: boolean;
function IsReferencedByNonLocation(rec: IwbMainRecord): boolean;
var
@ -50,9 +50,7 @@ begin
// Does not cover long chains of linked refs.
if (ReferencedByCount(referencingRecord) = 0) then begin
if (sig = 'REFR') then begin
if Equals(LinksTo(ElementByPath(rec, 'Cell')), LinksTo(ElementByPath(referencingRecord, 'Cell'))) then begin
continue;
end;
if InSameCell(rec, referencingRecord) then continue;
end;
end;
@ -66,6 +64,61 @@ begin
end;
end;
function InSameCell(ref: IwbMainRecord; otherRef: IwbMainRecord): boolean;
var
cell, otherCell, worldspace, otherWorldspace: IwbMainRecord;
coords, otherCoords: TwbGridCell;
begin
cell := LinksTo(ElementByPath(ref, 'Cell'));
otherCell := LinksTo(ElementByPath(otherRef, 'Cell'));
if not Assigned(otherCell) then exit;
// Interior cell
if (GetElementNativeValues(cell, 'DATA') and 1) > 0 then begin
result := Equals(cell, otherCell);
exit;
end;
worldspace := LinksTo(ElementByPath(cell, 'Worldspace'));
otherWorldspace := LinksTo(ElementByPath(otherCell, 'Worldspace'));
if not Equals(worldspace, otherWorldspace) then begin
result := false;
exit;
end;
// Consider small world a cell
if (GetElementNativeValues(worldspace, 'DATA') and 1) > 0 then begin
result := true;
exit;
end;
// Persistent refs are located in 0,0 so we detect their original grid position via their position
coords := wbPositionToGridCell(GetPosition(ref));
otherCoords := wbPositionToGridCell(GetPosition(otherRef));
result := (coords.x = otherCoords.x) and (coords.y = otherCoords.y);
end;
function HasScripts(e: IwbMainRecord; targetScripts: string): boolean;
var
scripts, currentItem: IwbElement;
linkedCount, i: integer;
begin
if not ElementExists(e, 'VMAD') then exit;
scripts := ElementByPath(e, 'VMAD\Scripts');
for i := 0 to Pred(ElementCount(scripts)) do begin
currentItem := ElementByIndex(scripts, i);
if Pos(GetElementEditValues(currentItem, 'ScriptName'), targetScripts) <> 0 then begin
result := true;
break;
end;
end;
end;
function MarkPersistent(e: IwbMainRecord): boolean;
begin
AddMessage(' + Marking as persistent: ' + GetElementEditValues(e, 'NAME') + ' - (' + Name(e) + ')');
@ -113,6 +166,33 @@ begin
end;
end;
function IsLinkedRefRemote(e: IwbMainRecord; linkedRefKeyword: IwbMainRecord): boolean;
var
linkedRef: IwbMainRecord;
begin
result := true;
if Assigned(linkedRefKeyword) then begin
linkedRef := GetLinkedRef(e, linkedRefKeyword);
end
else begin
linkedRef := GetLinkedRefNull(e);
end;
if Assigned(linkedRef) then begin
if InSameCell(e, linkedRef) then begin
//AddMessage(' Skipping actor, staying in one cell with his linked ref: ' + GetElementEditValues(e, 'NAME') + ' - (' + Name(e) + ')');
result := false;
end
else if not GetIsPersistent(linkedRef) then begin
MarkPersistent(linkedRef);
end;
end
else begin
// Missing linked ref. Usually, package checks for its presence. Sometimes, it's just missing. The outcome is the same, this package is not doing anything.
result := false;
end;
end;
function Process(e: IInterface): integer;
var
currentPlugin: IwbFile;
@ -122,10 +202,10 @@ var
sig, baseSig, packageLoc, packageType: string;
isREFR, isACHR, skip: boolean;
begin
if not pluginAnnounced then begin
if not pluginShown then begin
currentPlugin := GetFile(e);
AddMessage(#13#10 + '* Processing ' + Name(currentPlugin));
pluginAnnounced := true;
AddMessage(#13#10 + '# Processing ' + Name(currentPlugin));
pluginShown := true;
refsChecked := 0;
recordsCounted := 0;
flaggedCount := 0;
@ -139,7 +219,7 @@ begin
AddMessage(' ' + IntToStr(refsChecked) + ' references checked.');
AddMessage(' ' + IntToStr(persLocSkipped) + ' actors with Persistent Location skipped.');
AddMessage(' ' + IntToStr(flaggedCount) + ' references have been marked as persistent.' + #13#10);
pluginAnnounced := false;
pluginShown := false;
exit;
end;
@ -156,7 +236,7 @@ begin
if GetIsDeleted(e) then begin
if GetIsPersistent(e) then begin
AddMessage(' Removing persistence flag from deleted record: ' + ShortName(e));
AddMessage(' ! Removing persistence flag from deleted record: ' + ShortName(e));
SetIsPersistent(e, False);
end;
exit;
@ -224,62 +304,52 @@ begin
if packageCount = 0 then
exit;
skip := false;
skip := true;
for i := 0 to Pred(packageCount) do begin
package := LinksTo(ElementByIndex(packages, i));
if not Assigned(package) then begin
skip := true;
AddMessage(' ! WARNING: Invalid package entry: ' + GetElementEditValues(e, 'NAME') + ' - (' + Name(e) + ')');
continue;
end;
packageLoc := GetElementEditValues(ElementByIndex(ElementByPath(package, 'Package Data\Data Input Values'), 0), 'PLDT\Type');
if (packageLoc = 'Near editor location') or (packageLoc = 'Near self') then begin
AddMessage(' Skipping editor location actor: ' + GetElementEditValues(e, 'NAME') + ' - (' + Name(e) + ')');
skip := true;
continue;
end;
if packageLoc <> '' then begin
if (packageLoc = 'In cell') then begin
refCell := LinksTo(ElementByPath(ElementByIndex(ElementByPath(package, 'Package Data\Data Input Values'), 0), 'PLDT\Cell'));
if Assigned(refCell) then begin
if Equals(refCell, LinksTo(ElementByPath(e, 'Cell'))) then begin
AddMessage(' Skipping actor, staying in one cell: ' + GetElementEditValues(e, 'NAME') + ' - (' + Name(e) + ')');
skip := true;
continue;
end;
end;
end;
if (GetElementEditValues(ElementByIndex(ElementByPath(package, 'Package Data\Data Input Values'), 0), 'PTDA\Target Data\Type') = 'Linked Reference') then begin
linkedRefKeyword := LinksTo(ElementByPath(ElementByIndex(ElementByPath(package, 'Package Data\Data Input Values'), 0), 'PTDA\Target Data\Reference'));
if Assigned(linkedRefKeyword) then begin
linkedRef := GetLinkedRef(e, linkedRefKeyword);
if (packageLoc = 'Near editor location') or (packageLoc = 'Near self') then begin
//AddMessage(' Skipping editor location actor: ' + GetElementEditValues(e, 'NAME') + ' - (' + Name(e) + ')');
continue;
end
else begin
linkedRef := GetLinkedRefNull(e);
end;
if Assigned(linkedRef) then begin
if Equals(LinksTo(ElementByPath(linkedRef, 'Cell')), LinksTo(ElementByPath(e, 'Cell'))) then begin
AddMessage(' Skipping actor, staying in one cell with his linked ref: ' + GetElementEditValues(e, 'NAME') + ' - (' + Name(e) + ')');
skip := true;
continue;
else if (packageLoc = 'In cell') then begin
refCell := LinksTo(ElementByPath(ElementByIndex(ElementByPath(package, 'Package Data\Data Input Values'), 0), 'PLDT\Cell'));
if Assigned(refCell) then begin
if Equals(refCell, LinksTo(ElementByPath(e, 'Cell'))) then continue;
end;
end
else if (packageLoc = 'Near linked reference') then begin
linkedRefKeyword := LinksTo(ElementByPath(ElementByIndex(ElementByPath(package, 'Package Data\Data Input Values'), 0), 'PLDT\Keyword'));
if not IsLinkedRefRemote(e, linkedRefKeyword) then continue;
end
else if (packageLoc = 'Near reference') then begin
if InSameCell(e, LinksTo(ElementByPath(ElementByIndex(ElementByPath(package, 'Package Data\Data Input Values'), 0), 'PLDT\Reference'))) then continue;
end;
end
else if (GetElementEditValues(ElementByIndex(ElementByPath(package, 'Package Data\Data Input Values'), 0), 'PTDA\Target Data\Type') = 'Linked Reference') then begin
linkedRefKeyword := LinksTo(ElementByPath(ElementByIndex(ElementByPath(package, 'Package Data\Data Input Values'), 0), 'PTDA\Target Data\Reference'));
if not IsLinkedRefRemote(e, linkedRefKeyword) then continue;
end;
skip := false;
end;
if skip then exit;
if skip then begin
//AddMessage(' Skipping actor, staying in one cell: ' + GetElementEditValues(e, 'NAME') + ' - (' + Name(e) + ')');
exit;
end;
MarkPersistent(e);