Jump to content

[WIPz] TES5Edit


zilav

Recommended Posts

 

It is caused by floating point rounding and the fact that those fields are stored as scaled integers inside plugin. Besides 0.01 doesn't make difference anywhere.

 

How does the scalar 9.680000 round up to 9.690000? Only if its 9.685000-9.689999.

If it's only 2 significant digits then 9.680000 would round up to 9.700000- but  then why not just display 9.68 or 9.69 for three significant digits?

Link to comment
Share on other sites

Because floating point storage and representation does not obey your desire for logical outcomes? :P

Link to comment
Share on other sites

Hi

 

I am seeing some severe slowdowns with r1573 when copying records.

 

For example "Copy as new record into..." Static from skyrim.esm into a new mod.

 

r1573 needs 10 minutes

[00:13] [stuff.esp] Adding master "Skyrim.esm"

[10:33] Copying done.

 

3.0.31 needs seconds

[00:15] [stuf1.esp] Adding master "Skyrim.esm"

[00:18] Copying done.

 

Thanks for all

 

Yep we know, being investigated. Though this is the reason why 3.0.32 is not released yet and killed kittens :evil:

There is also a minor visual glitch (missing lod geometry when up close) with lodgen that needs to be fixed.

  • Like 1
Link to comment
Share on other sites

Is this slow copy thing with a specific record or type of record? I just did several randomly picked Static entries and each one says it took about 6 seconds to finish.

Link to comment
Share on other sites

Is this slow copy thing with a specific record or type of record? I just did several randomly picked Static entries and each one says it took about 6 seconds to finish.

 

The timing example of 10 minutes was copying the entire tree - all statics. Seemed a good test case :)

Link to comment
Share on other sites

This is a not working script, I tried to create it from your description, but nothing were matching up when running on vanilla skyrim navmeshes. That's why I asked for more information.

OK, I've figured it out.

 

Each Triangle has 3 Edges, which you've numbered Triangle #0, Triangle #1, Triangle #2.

 

But you numbered the unknown Flags as 1, 2, 3 -- they should probably be 0 relative. And I got confused by the position around the edge where the flag appears. That's just happenstance, although the CK does exhibit some consistency in assigning edges.

 

Actually, it's quite simple: Flag 1 (now External1) should be Edge0External,  Flag 2 (now External2Mid) should be Edge1External, Flag 3 (now External3End) should be Edge2External.

 

If Flag 1 Edge0External is set, then Edges\Triangle#0 doesn't have a triangle number in it. Instead, it has an External Connection number.

 

Then, the External Connections\Connection # has the external mesh and the triangle in that external mesh.

 

Right now, the Edges labels are confusing. OK for the common case, but wrong for the externals. Could we have Edges\Edge, just like Vertices\Vertex?

 

How hard would it be to change the orthography for external connection numbers? Perhaps "{ nn }"?

 

UPDATE: Maybe anywhere a triangle is referenced, Triangle #nn, and for external External #nn? (Triangle and External having the same number of letters.)

Triangle #613
|- Edges
|  |- Edge #0 (0<->1) Triangle #614
|  |- Edge #1 (1<->2) -1
|  |- Edge #2 (2<->0) External #23
|- Flags
|  |- Edge2External
External Connections
External #23
|- Unknown
|- Mesh      [...]
|- Triangle  Triangle #166
Link to comment
Share on other sites

In the External Connections table, the Mesh can be the same as the current mesh. That is, this isn't necessarily "external" -- or symmetric. This is how they do jumps down from ledges for NPCs; one-way links through this table. It may have something to do with Cover Edges values, too.

Link to comment
Share on other sites

How do I access Edges?

 

 

    flags := GetElementNativeValues(tri, 'Flags');
    // triangle has external connections?
    if flags and 1 > 0 then begin
      edges = ElementByPath(tri, 'Edges');
      ExtNumber := GetElementNativeValues(edges, 'Triangle #0 (0 <-> 1)');
 

Or can that be an array? An array would be more convenient!

      ExtNumber := ElementByIndex(edges, 0);
Link to comment
Share on other sites

You need to access the triangle member of the edges array:

 

edges := ElementByPath(tri, 'Edges');

edgeTri := ElementByIndex(edges, 0);

ExtNumber := GetElementNativeValues(edgeTri, '(0 <-> 1)');

Link to comment
Share on other sites

After staring at navmeshes for some time, I'm actually thinking about making themt more linear

 

9YNE4Ie.png

 

It is easier on eyes, eaiser to access from script, 2 less rows per triangle so more fit on screen. The only drawback is incompatibility with scripts working with navmeshes, but I don't know of any. Also since there is no easy way to change node names in xEdit (wbUnions are bad idea here with hundreds of elements), I think of naming flags as in screenshot. It clearly tells that edge is an index, not triangle.

Any thoughts?

  • Like 1
Link to comment
Share on other sites

After staring at navmeshes for some time, I'm actually thinking about making themt more linear

 

It is easier on eyes, eaiser to access from script, 2 less rows per triangle so more fit on screen. The only drawback is incompatibility with scripts working with navmeshes, but I don't know of any. Also since there is no easy way to change node names in xEdit (wbUnions are bad idea here with hundreds of elements), I think of naming flags as in screenshot. It clearly tells that edge is an index, not triangle.

Any thoughts?

 

Looks OK. I don't know of any scripts for navmeshes other than the ones we've been trading.

 

How would I know the flag numbers? Are there constants we can OR together to make 7, but also use them for "flags and 'Edge 1 <-> 2 external index'"?

 

Please, just get rid of the "external index" -- since I've now determined that they are sometimes internal (one-way jumps within the same Mesh). We could rename the External Connections table to Edge Links, and the flags to 'Edge 1..2 link'.

 

Pascal syntax would be a heck of a lot easier to type than '1 <-> 2'. (I kept getting the shifts and spacing wrong in my efforts: 1 space shift < unshift - shift > space 2.)

 

EDIT: or Edge 1_2 (say edge 1 bar 2).

Link to comment
Share on other sites

You need to access the triangle member of the edges array:

 

edges := ElementByPath(tri, 'Edges');

edgeTri := ElementByIndex(edges, 0);

ExtNumber := GetElementNativeValues(edgeTri, '(0 <-> 1)');

Using a variant of this, I've been able to re-build the (Zilav) script to test bi-directional external connections (or lack thereof). It should be easily modifiable for the new layout and names, too. Takes my machine 48 minutes to run. But might be speedier: Zilav looped through the tri table. Next run, I'm going to try it without a loop, just a simpler bounds check instead.

Link to comment
Share on other sites

Uploaded a new version with performance issue fix when copying records and renamed NAVM fields.

 

Using a variant of this, I've been able to re-build the (Zilav) script to test bi-directional external connections (or lack thereof). It should be easily modifiable for the new layout and names, too. Takes my machine 48 minutes to run. But might be speedier: Zilav looped through the tri table. Next run, I'm going to try it without a loop, just a simpler bounds check instead.

It is slow because I thought that external connection in triangle IS triangle index, so to get an index in connections I needed to loop through all triangles pripor to it and count the number of external ones. Now this loop can be removed entirely and should speed up script by a lot.

You can (and have to) use binary arithmetics so AND 7 > 0 will work to check edge link flags.

  • Like 1
Link to comment
Share on other sites

Now this loop can be removed entirely and should speed up script by a lot.

You can (and have to) use binary arithmetics so AND 7 > 0 will work to check edge link flags.

Yeah, without the loop cut time to 21:19.

Either there are more things to decode, or Skyrim.esm is in terrible shape. Roughly 32,800 errors!

 

Since I tested for everything, here are some amazing problems:

	Line 4888: Referenced triangle (1012 > 988) in [NAVM:000EAECC] (in GRUP Cell Temporary Children of IlinaltasDeepExterior01 [CELL:00009B36] (in Tamriel "Skyrim" [WRLD:0000003C] at -8,-12)) is too large!
	Line 4891: Referenced triangle (1011 > 988) in [NAVM:000EAECC] (in GRUP Cell Temporary Children of IlinaltasDeepExterior01 [CELL:00009B36] (in Tamriel "Skyrim" [WRLD:0000003C] at -8,-12)) is too large!
	Line 24020: Referenced triangle (422 > 415) in [NAVM:0010F989] (in GRUP Cell Temporary Children of [CELL:00009698] (in Tamriel "Skyrim" [WRLD:0000003C] at 3,-7)) is too large!
	Line 24022: Referenced triangle (428 > 415) in [NAVM:0010F989] (in GRUP Cell Temporary Children of [CELL:00009698] (in Tamriel "Skyrim" [WRLD:0000003C] at 3,-7)) is too large!
	Line 24024: Referenced triangle (424 > 415) in [NAVM:0010F989] (in GRUP Cell Temporary Children of [CELL:00009698] (in Tamriel "Skyrim" [WRLD:0000003C] at 3,-7)) is too large!
	Line 24026: Referenced triangle (425 > 415) in [NAVM:0010F989] (in GRUP Cell Temporary Children of [CELL:00009698] (in Tamriel "Skyrim" [WRLD:0000003C] at 3,-7)) is too large!
	Line 24028: Referenced triangle (421 > 415) in [NAVM:0010F989] (in GRUP Cell Temporary Children of [CELL:00009698] (in Tamriel "Skyrim" [WRLD:0000003C] at 3,-7)) is too large!
	Line 24030: Referenced triangle (423 > 415) in [NAVM:0010F989] (in GRUP Cell Temporary Children of [CELL:00009698] (in Tamriel "Skyrim" [WRLD:0000003C] at 3,-7)) is too large!
	Line 24032: Referenced triangle (416 > 415) in [NAVM:0010F989] (in GRUP Cell Temporary Children of [CELL:00009698] (in Tamriel "Skyrim" [WRLD:0000003C] at 3,-7)) is too large!
	Line 24034: Referenced triangle (427 > 415) in [NAVM:0010F989] (in GRUP Cell Temporary Children of [CELL:00009698] (in Tamriel "Skyrim" [WRLD:0000003C] at 3,-7)) is too large!
	Line 24036: Referenced triangle (418 > 415) in [NAVM:0010F989] (in GRUP Cell Temporary Children of [CELL:00009698] (in Tamriel "Skyrim" [WRLD:0000003C] at 3,-7)) is too large!
	Line 24038: Referenced triangle (419 > 415) in [NAVM:0010F989] (in GRUP Cell Temporary Children of [CELL:00009698] (in Tamriel "Skyrim" [WRLD:0000003C] at 3,-7)) is too large!
	Line 24040: Referenced triangle (430 > 415) in [NAVM:0010F989] (in GRUP Cell Temporary Children of [CELL:00009698] (in Tamriel "Skyrim" [WRLD:0000003C] at 3,-7)) is too large!
Examining one in detail,

Triangle 22 in [NAVM:000FD7E8] (in GRUP Cell Temporary Children of [CELL:00009B37] (in Tamriel "Skyrim" [WRLD:0000003C] at -9,-12)) is broken
Triangle 46 in [NAVM:000FD7E8] (in GRUP Cell Temporary Children of [CELL:00009B37] (in Tamriel "Skyrim" [WRLD:0000003C] at -9,-12)) is broken
Triangle 157 in [NAVM:000FD7E8] (in GRUP Cell Temporary Children of [CELL:00009B37] (in Tamriel "Skyrim" [WRLD:0000003C] at -9,-12)) is broken
Triangle 260 in [NAVM:000FD7E8] (in GRUP Cell Temporary Children of [CELL:00009B37] (in Tamriel "Skyrim" [WRLD:0000003C] at -9,-12)) is broken
Referenced triangle (1012 > 988) in [NAVM:000EAECC] (in GRUP Cell Temporary Children of IlinaltasDeepExterior01 [CELL:00009B36] (in Tamriel "Skyrim" [WRLD:0000003C] at -8,-12)) is too large!
Triangle 267 in [NAVM:000FD7E8] (in GRUP Cell Temporary Children of [CELL:00009B37] (in Tamriel "Skyrim" [WRLD:0000003C] at -9,-12)) is broken
Triangle 519 in [NAVM:000FD7E8] (in GRUP Cell Temporary Children of [CELL:00009B37] (in Tamriel "Skyrim" [WRLD:0000003C] at -9,-12)) is broken
Referenced triangle (1011 > 988) in [NAVM:000EAECC] (in GRUP Cell Temporary Children of IlinaltasDeepExterior01 [CELL:00009B36] (in Tamriel "Skyrim" [WRLD:0000003C] at -8,-12)) is too large!
Triangle 16 in [NAVM:000FD7E9] (in GRUP Cell Temporary Children of [CELL:00009B37] (in Tamriel "Skyrim" [WRLD:0000003C] at -9,-12)) is broken
Verified that Triangle 267 in [NAVM:000FD7E8] uses Edge Link #14, which does have 1012 value.

Verified that Triangle 16 in [NAVM:000FD7E9] uses Edge Link #0, which does have 1011 value.

Verified there are only 988 triangles in [NAVM:000EAECC].

In the CK, as soon as I load up that navmesh and use find triangle 267, it starts spamming PATHFINDING warnings. Looks like it's supposed to connect to 000EAECC Tri 209.

Could somebody else verify these in their copy? Is mine corrupted?

Link to comment
Share on other sites

To keep it simpler, here's all the errors from Update.esm. "broken" means it couldn't find the matching link back.

[EDIT: list removed]

It looks to me that the whole point of these changes in Update.esm was to add Links. All of these navmesh blocks add new Edge links flags. But it looks like some adjacent navmeshes with the new links weren't added!?!?

 

I've posted these examples here to ensure that folks can verify the problems, and because this verifies the new code for tables and flags is correct. For detailed analysis of bugs, should be a new thread.

UPDATE: It appears that those errors have already been fixed by USKP, so I've removed them. So much can be done with a few well placed Finalizes.

Link to comment
Share on other sites

Yeah, without the loop cut time to 21:19.

Either there are more things to decode, or Skyrim.esm is in terrible shape. Roughly 32,800 errors!

Skyrim.esm is in terrible shape. Just about any time I have to finalize a navmesh somewhere, one or more of the adjacent cells begins throwing errors and I go to look and find things broken. 32800 errors may seem like a lot, but they pile up fast when each cell you run into has a dozen or more errors to fix.

Link to comment
Share on other sites

Skyrim.esm is in terrible shape. Just about any time I have to finalize a navmesh somewhere, one or more of the adjacent cells begins throwing errors and I go to look and find things broken. 32800 errors may seem like a lot, but they pile up fast when each cell you run into has a dozen or more errors to fix.

And the actual number will be less than that, as the other side of the link may be pointing in the wrong place too, doubling the errors. But those I've examined don't have the other side.

 

Also, some of the errors give 2 lines.

 

Anyway, I'm going to reformat the output -- Zilav has the result at the far right, better to put it on the left to avoid scrolling. Then I'll post the data and a Meta tracker for cleaning things up. It's going to take awhile!

Link to comment
Share on other sites

After adding prettier multi-line error messages, my current run only found a few dozen errors total. My previous code must have had a false positive in it -- or my current code has a false negative....

 

{
    Check that Edge Linked triangles in navmeshes are pointing to each other
}
unit NavMeshCheckExternal;

//===========================================================================
function Initialize: integer;
begin
    if wbSimpleRecords then begin
        MessageDlg('Simple records must be unchecked in xEdit options', mtInformation, [mbOk], 0);
        Result := 1;
        Exit;
    end;
end;

//===========================================================================
// check that tri1 in navmesh navm1 points to tri2 in navmesh navm2
function CheckConnection(navm1, navm2: IInterface; tri1, tri2: integer): Boolean;
var
    tris, tri, EdgeLinks, EdgeLink: IInterface;
    TriLimit, flags, EdgeLinkLimit, EdgeLinkIndex: integer;
begin
    if Signature(navm1) <> 'NAVM'
    then begin
        AddMessage('Not NAVM!');
        AddMessage(Format('Referenced triangle %d in %s', [tri1, Name(navm1)]));
        Exit;
        end;

    tris := ElementByPath(navm1, 'NVNM\Triangles');
    TriLimit := Pred(ElementCount(tris));
    EdgeLinks := ElementByPath(navm1, 'NVNM\Edge Links');
    EdgeLinkLimit := Pred(ElementCount(EdgeLinks));

    if tri1 > TriLimit
    then begin
        AddMessage(Format('Referenced triangle (%d > %d) in %s', [tri1, TriLimit, Name(navm1)]));
        Exit;
        end;
    tri := ElementByIndex(tris, tri1);
    flags := GetElementNativeValues(tri, 'Flags');

    if flags and 7 = 0
    then begin
        AddMessage('No Edge Links');
        AddMessage(Format('Referenced triangle %d in %s', [tri1, Name(navm1)]));
        Exit;
        end;

    if flags and 1 > 0
    then begin
        EdgeLinkIndex := GetElementNativeValues(tri, 'Edge 0-1');
        if EdgeLinkIndex > EdgeLinkLimit
        then begin
            AddMessage(Format('Bad Edge 0-1 link (%d > %d)!', [EdgeLinkIndex, EdgeLinkLimit]));
            AddMessage(Format('Referenced triangle %d in %s', [tri1, Name(navm1)]));
            end
        else begin
            EdgeLink := ElementByIndex(EdgeLinks, EdgeLinkIndex);
            if (FormID(LinksTo(ElementByName(EdgeLink, 'Mesh'))) = FormID(navm2)) and (GetElementNativeValues(EdgeLink, 'Triangle') = tri2)
            then begin
                Result := True;
                Exit;
                end;
            end;
        end;
    if flags and 2 > 0
    then begin
        EdgeLinkIndex := GetElementNativeValues(tri, 'Edge 1-2');
        if EdgeLinkIndex > EdgeLinkLimit
        then begin
            AddMessage(Format('Bad Edge 1-2 link (%d > %d)!', [EdgeLinkIndex, EdgeLinkLimit]));
            AddMessage(Format('Referenced triangle %d in %s', [tri1, Name(navm1)]));
            end
        else begin
            EdgeLink := ElementByIndex(EdgeLinks, EdgeLinkIndex);
            if (FormID(LinksTo(ElementByName(EdgeLink, 'Mesh'))) = FormID(navm2)) and (GetElementNativeValues(EdgeLink, 'Triangle') = tri2)
            then begin
                Result := True;
                Exit;
                end;
            end;
        end;
    if flags and 4 > 0
    then begin
        EdgeLinkIndex := GetElementNativeValues(tri, 'Edge 2-0');
        if EdgeLinkIndex > EdgeLinkLimit
        then begin
            AddMessage(Format('Bad Edge 2-0 link (%d > %d)!', [EdgeLinkIndex, EdgeLinkLimit]));
            AddMessage(Format('Referenced triangle %d in %s', [tri1, Name(navm1)]));
            end
        else begin
            EdgeLink := ElementByIndex(EdgeLinks, EdgeLinkIndex);
            if (FormID(LinksTo(ElementByName(EdgeLink, 'Mesh'))) = FormID(navm2)) and (GetElementNativeValues(EdgeLink, 'Triangle') = tri2)
            then begin
                Result := True;
                Exit;
                end;
            end;
        end;

    AddMessage('No Edge Link match!');
    AddMessage(Format('Referenced triangle %d in %s', [tri1, Name(navm1)]));
end;


//===========================================================================
function Process(e: IInterface): integer;
var
    tris, tri, EdgeLinks, EdgeLink: IInterface;
    i, flags, EdgeLinkLimit, EdgeLinkIndex, EdgeLinkFound, EdgeLinkCount, errors: integer;
begin
    if Signature(e) <> 'NAVM'
    then Exit;

    tris := ElementByPath(e, 'NVNM\Triangles');
    EdgeLinks := ElementByPath(e, 'NVNM\Edge Links');
    EdgeLinkCount := ElementCount(EdgeLinks);
    EdgeLinkLimit := Pred(ElementCount(EdgeLinks));
    EdgeLinkFound := 0;

    // iterate through triangles
    for i := 0 to Pred(ElementCount(tris))
    do begin
        errors := 0;
        tri := ElementByIndex(tris, i);
        flags := GetElementNativeValues(tri, 'Flags');

        // triangle has EdgeLinks?
        if flags and 1 > 0
        then begin
            EdgeLinkIndex := GetElementNativeValues(tri, 'Edge 0-1');
            if EdgeLinkIndex > EdgeLinkLimit
            then begin
                AddMessage(Format('Bad Edge 0-1 link (%d > %d)!', [EdgeLinkIndex, EdgeLinkLimit]));
                end
            else begin
                EdgeLink := ElementByIndex(EdgeLinks, EdgeLinkIndex);
                if not CheckConnection(LinksTo(ElementByName(EdgeLink, 'Mesh')), e, GetElementNativeValues(EdgeLink, 'Triangle'), i)
                then begin
                    AddMessage(Format('via Edge 0-1 link %d', [EdgeLinkIndex]));
                    Inc(errors);
                    end;
                end;
            Inc(EdgeLinkFound);
            end;
        if flags and 2 > 0
        then begin
            EdgeLinkIndex := GetElementNativeValues(tri, 'Edge 1-2');
            if EdgeLinkIndex > EdgeLinkLimit
            then begin
                AddMessage(Format('Bad Edge 1-2 link (%d > %d)!', [EdgeLinkIndex, EdgeLinkLimit]));
                end
            else begin
                EdgeLink := ElementByIndex(EdgeLinks, EdgeLinkIndex);
                if not CheckConnection(LinksTo(ElementByName(EdgeLink, 'Mesh')), e, GetElementNativeValues(EdgeLink, 'Triangle'), i)
                then begin
                    AddMessage(Format('via Edge 1-2 link %d', [EdgeLinkIndex]));
                    Inc(errors);
                    end;
                end;
            Inc(EdgeLinkFound);
            end;
        if flags and 4 > 0
        then begin
            EdgeLinkIndex := GetElementNativeValues(tri, 'Edge 2-0');
            if EdgeLinkIndex > EdgeLinkLimit
            then begin
                AddMessage(Format('Bad Edge 2-0 link (%d > %d)!', [EdgeLinkIndex, EdgeLinkLimit]));
                end
            else begin
                EdgeLink := ElementByIndex(EdgeLinks, EdgeLinkIndex);
                if not CheckConnection(LinksTo(ElementByName(EdgeLink, 'Mesh')), e, GetElementNativeValues(EdgeLink, 'Triangle'), i)
                then begin
                    AddMessage(Format('via Edge 2-0 link %d', [EdgeLinkIndex]));
                    Inc(errors);
                    end;
                end;
            Inc(EdgeLinkFound);
            end;
        if errors > 0
        then begin
            AddMessage(Format('^^^ Error triangle %d in %s', [i, Name(e)]));
            //Result := 1;
            //Exit;
            end;
        end;
    if (EdgeLinkFound > 0) and (EdgeLinkFound > EdgeLinkCount)
    then begin
        AddMessage(Format('Too many Edges Linked (%d > %d) in %s', [EdgeLinkFound, EdgeLinkCount, Name(e)]));
        //Result := 1;
        //Exit;
        end;
end;

end.
Link to comment
Share on other sites

Took 13 minutes to scan Skyrim.esm on my PC.

Also refactored it a bit, and probably going to include with TES5Edit if you don't mind.

p.s. sorry for refactoring, I just not used to your identations style. But it is smaller now, so won't be much work to change it back.

{
    Check that Edge Linked triangles in navmeshes are pointing to each other
}
unit NavMeshCheckExternal;

var
  arEdge: array [0..2] of string;

//===========================================================================
function Initialize: integer;
begin
  if wbSimpleRecords then begin
    MessageDlg('Simple records must be unchecked in xEdit options', mtInformation, [mbOk], 0);
    Result := 1;
    Exit;
  end;
  arEdge[0] := '0-1';
  arEdge[1] := '1-2';
  arEdge[2] := '2-0';
end;

//===========================================================================
// check that tri1 in navmesh navm1 points to tri2 in navmesh navm2
function CheckConnection(navm1, navm2: IInterface; tri1, tri2: integer): Boolean;
var
  tris, tri, EdgeLinks, EdgeLink: IInterface;
  TriLimit, j, flags, EdgeLinkLimit, EdgeLinkIndex: integer;
begin
  if Signature(navm1) <> 'NAVM' then begin
    AddMessage('Not NAVM!');
    AddMessage(Format('Referenced triangle %d in %s', [tri1, Name(navm1)]));
    Exit;
  end;
  tris := ElementByPath(navm1, 'NVNM\Triangles');
  TriLimit := Pred(ElementCount(tris));
  EdgeLinks := ElementByPath(navm1, 'NVNM\Edge Links');
  EdgeLinkLimit := Pred(ElementCount(EdgeLinks));
  if tri1 > TriLimit then begin
    AddMessage(Format('Referenced triangle (%d > %d) in %s', [tri1, TriLimit, Name(navm1)]));
    Exit;
  end;
  tri := ElementByIndex(tris, tri1);
  flags := GetElementNativeValues(tri, 'Flags');
  if flags and 7 = 0 then begin
    AddMessage('No Edge Links');
    AddMessage(Format('Referenced triangle %d in %s', [tri1, Name(navm1)]));
    Exit;
  end;

  for j := 0 to 2 do
    if flags and (1 shl j) > 0 then begin
      EdgeLinkIndex := GetElementNativeValues(tri, 'Edge ' + arEdge[j]);
      if EdgeLinkIndex > EdgeLinkLimit then begin
        AddMessage(Format('Bad Edge %s link (%d > %d)!', [arEdge[j], EdgeLinkIndex, EdgeLinkLimit]));
        AddMessage(Format('Referenced triangle %d in %s', [tri1, Name(navm1)]));
      end
      else begin
        EdgeLink := ElementByIndex(EdgeLinks, EdgeLinkIndex);
        if (FormID(LinksTo(ElementByName(EdgeLink, 'Mesh'))) = FormID(navm2)) and (GetElementNativeValues(EdgeLink, 'Triangle') = tri2) then begin
          Result := True;
          Exit;
        end;
      end;
    end;

  AddMessage('No Edge Link match!');
  AddMessage(Format('Referenced triangle %d in %s', [tri1, Name(navm1)]));
end;


//===========================================================================
function Process(e: IInterface): integer;
var
  tris, tri, EdgeLinks, EdgeLink: IInterface;
  i, j, flags, EdgeLinkLimit, EdgeLinkIndex, EdgeLinkFound, EdgeLinkCount, errors: integer;
begin
  if Signature(e) <> 'NAVM' then
    Exit;

  tris := ElementByPath(e, 'NVNM\Triangles');
  EdgeLinks := ElementByPath(e, 'NVNM\Edge Links');
  EdgeLinkCount := ElementCount(EdgeLinks);
  EdgeLinkLimit := Pred(ElementCount(EdgeLinks));
  EdgeLinkFound := 0;

  // iterate through triangles
  for i := 0 to Pred(ElementCount(tris)) do begin
    errors := 0;
    tri := ElementByIndex(tris, i);
    flags := GetElementNativeValues(tri, 'Flags');
    for j := 0 to 2 do
      // triangle has EdgeLinks?
      if flags and (1 shl j) > 0 then begin
        EdgeLinkIndex := GetElementNativeValues(tri, 'Edge ' + arEdge[j]);
        if EdgeLinkIndex > EdgeLinkLimit then
          AddMessage(Format('Bad Edge %s link (%d > %d)!', [arEdge[j], EdgeLinkIndex, EdgeLinkLimit]))
        else begin
          Inc(EdgeLinkFound);
          EdgeLink := ElementByIndex(EdgeLinks, EdgeLinkIndex);
          if not CheckConnection(LinksTo(ElementByName(EdgeLink, 'Mesh')), e, GetElementNativeValues(EdgeLink, 'Triangle'), i) then begin
            AddMessage(Format('via Edge %s link %d', [arEdge[j], EdgeLinkIndex]));
            Inc(errors);
          end;
        end;
      end;

    if errors > 0 then
      AddMessage(Format('^^^ Error triangle %d in %s', [i, Name(e)]));
  end;
    
  if (EdgeLinkFound > 0) and (EdgeLinkFound > EdgeLinkCount) then begin
    AddMessage(Format('Too many Edges Linked (%d > %d) in %s', [EdgeLinkFound, EdgeLinkCount, Name(e)]));
    //Result := 1;
    //Exit;
  end;
end;

end.
  • Haha 1
Link to comment
Share on other sites

 

Took 13 minutes to scan Skyrim.esm on my PC.

Also refactored it a bit, and probably going to include with TES5Edit if you don't mind.

p.s. sorry for refactoring, I just not used to your identations style. But it is smaller now, so won't be much work to change it back.

Sure, go ahead and include it! Likewise, your indentation style looks odd to me, too. (I've been doing Pascal since 1976, UCSD Pascal on the Terak circa 1978, then Borland in the 80s.) The PC editor automatically prefers 4 space indentation, which is what we used on the Terak. And we always taught "then begin" matching "else begin" on a new line. But as long as it works, I doubt anybody will be looking at it.

 

How would I get it to run over the whole Skyrim, but using the selected plugins? If I load USKP, and run it on USKP, I get only the USKP NAVM records. If I load USKP, and run it on Skyrim.esm, I get the same identical results as running without USKP loaded.

 

I'd like to put my effort into fixing those that haven't already been fixed by USKP. Of course, maybe these haven't been fixed, so they really are identical.

 

Next up, I'm going to write NavMeshCheckInternal to bulk find all the bad internal edges....

Link to comment
Share on other sites

I'm beginning to suspect a pattern in the fixes. Deleting a triangle during editing causes renumbering; looks like CK will simply grab the highest number and change it to the number just deleted (keeping the table compact and sequential). However, that number could be a border triangle -- but obviously the CK doesn't then automatically Finalize the cell to update the link table in adjoining cells, it depends on the intelligent user to do it.

 

Running a script on a plugin, it only "sees" the plugin tables. How do I access the underlying master record tables to see whether a triangle with the same border vertices has changed its number?

 

Also, how do I test whether the table I'm accessing is in the plugin or falling through to the master?

Link to comment
Share on other sites

Also, how do I test whether the table I'm accessing is in the plugin or falling through to the master?

It's definitely *NOT* falling through to the master. Running the script on a plugin generates errors for all the border connections.

How to I make LinksTo(ElementByName(EdgeLink, 'Mesh')) return tables from Update and Skyrim?

And again, how do I know it has?

Link to comment
Share on other sites

Updated it to check only winning overrides of navmeshes (last loaded)

http://pastebin.com/RCZYMVAM

Thanks.

 

Next up, I'm going to write NavMeshCheckInternal to bulk find all the bad internal edges....

Here's my replacement for both external and internal. Since we're looping through all the triangles in the game, might as well check all the edges at once.

 

I've tried to stick to your style. But it reminded me why we taught that all <statement> should have "begin" <statements> "end", even for single statements. Damn difficult to keep track of dangling semi-colons, and annoying to have to change program structure merely to add debugging.

 

[old code removed]

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...