Compilation 6 -> 0 avertissement, cuisson 3 -> 0 ; diff independant 6/6, 0 autre objet modifie. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
116 lines
6 KiB
Python
116 lines
6 KiB
Python
import re,sys,collections
|
|
def parse(p):
|
|
objs={}; pkg=None; key=None
|
|
for line in open(p,encoding='utf-8'):
|
|
line=line.rstrip('\n')
|
|
if line.startswith('##### '): pkg=line[6:]; continue
|
|
m=re.match(r'^ (\S+) \[(\w+)\]$',line)
|
|
if m: key=(pkg,m.group(1)); objs[key]={'cls':m.group(2),'lines':[]}; continue
|
|
if key: objs[key]['lines'].append(line)
|
|
return objs
|
|
# Profils de remplacement : selection des anciens et nouveaux noeuds, correspondance des broches.
|
|
# Usage : DiffRemplacementNoeuds.py avant.txt apres.txt [L7a|L7b] (L7a par defaut)
|
|
PROFILS={
|
|
'L7a':{'old':('K2Node_VariableGet',lambda l:'Engine.SkinnedMeshComponent\'",MemberName="SkeletalMesh"' in l),
|
|
'new':('K2Node_CallFunction',lambda l:'MemberName="GetSkeletalMesh"' in l and 'LPMeshCompat' in l),
|
|
'pins':[('self','Component'),('SkeletalMesh','ReturnValue')]},
|
|
'L7b':{'old':('K2Node_CallFunction',lambda l:'MemberName="K2_GetRandomPointInNavigableRadius"' in l),
|
|
'new':('K2Node_CallFunction',lambda l:'MemberName="GetRandomLocationInNavigableRadius"' in l and 'LPNavigationHelpers' in l),
|
|
'pins':[(x,x) for x in ('WorldContextObject','Origin','RandomLocation','Radius','NavData','FilterClass','ReturnValue')]},
|
|
}
|
|
PROFIL=PROFILS[sys.argv[3] if len(sys.argv)>3 else 'L7a']
|
|
A=parse(sys.argv[1]); B=parse(sys.argv[2])
|
|
def graph(path): return path.split(':')[-1].split('.')[0] if ':' in path else ''
|
|
def iscopy(path):
|
|
g=graph(path); return "ExecuteUbergraph" in g or g.endswith("_MERGED") or re.fullmatch(r"EdGraph_[0-9]+",g) is not None
|
|
def pos(o):
|
|
x=y='0'
|
|
for l in o['lines']:
|
|
if l.startswith(' NodePosX = '): x=l.split('= ')[1]
|
|
if l.startswith(' NodePosY = '): y=l.split('= ')[1]
|
|
return x,y
|
|
def select(D,sel): return {k:v for k,v in D.items() if v['cls']==sel[0] and not iscopy(k[1]) and any(sel[1](l) for l in v['lines'])}
|
|
old=select(A,PROFIL['old']); new=select(B,PROFIL['new'])
|
|
print('anciens noeuds',len(old),'nouveaux',len(new))
|
|
idx={(k[0],k[1].rsplit('.',1)[0],pos(v)):k for k,v in new.items()}
|
|
ren={}; miss=0
|
|
for k,v in old.items():
|
|
t=idx.get((k[0],k[1].rsplit('.',1)[0],pos(v)))
|
|
if not t: miss+=1; continue
|
|
ren[(k[0],graph(k[1]),k[1].rsplit('.',1)[1])]=t[1].rsplit('.',1)[1]
|
|
print('apparies',len(ren),'non apparies',miss)
|
|
skip=re.compile(r'^ (NodeGuid|GraphGuid|ErrorType|ErrorMsg|bHasCompilerMessage|NodePosX|NodePosY) = ')
|
|
def norm(pkg,g,lines):
|
|
out=[]
|
|
for l in lines:
|
|
if skip.match(l): continue
|
|
for (p,gg,o),n in ren.items():
|
|
if p==pkg and gg==g:
|
|
for op,np_ in PROFIL['pins']: l=l.replace(o+'.'+op,n+'.'+np_)
|
|
out.append(canon(l,pkg,g))
|
|
return out
|
|
def canon(l,pkg=None,g=None):
|
|
if l.startswith(' pin ') and ' -> ' in l:
|
|
head,links=l.rsplit(' -> ',1)
|
|
return head+' -> '+', '.join(sorted(x for x in links.split(', ') if x))
|
|
if l.startswith(' Nodes = ('):
|
|
items=[x.strip('"') for x in l[len(' Nodes = ('):-1].split('","')]
|
|
if pkg is not None:
|
|
items=[x for x in items if not any(pkg==p2 and ("."+o+"'") in x and (":"+gg+".") in x for (p2,gg,o) in ren)]
|
|
items+=[ "NOUVEAU:"+pkg+":"+gg+"."+n for (p2,gg,o),n in ren.items() if p2==pkg and gg==g ]
|
|
else:
|
|
items=[("NOUVEAU:"+x.split("'/Game/")[0] if False else x) for x in items]
|
|
return ' Nodes = SET'+str(sorted(items))
|
|
return l
|
|
newnames={(k[0],graph(k[1]),k[1].rsplit('.',1)[1]) for k in new}
|
|
def canonB(k,l):
|
|
if l.startswith(' Nodes = ('):
|
|
items=[x.strip('"') for x in l[len(' Nodes = ('):-1].split('","')]
|
|
keep=[]; add=[]
|
|
for x in items:
|
|
nm=x.rsplit('.',1)[1].rstrip("'")
|
|
if (k[0],k[1].split(':')[-1],nm) in newnames: add.append("NOUVEAU:"+k[0]+":"+k[1].split(':')[-1]+"."+nm)
|
|
else: keep.append(x)
|
|
return ' Nodes = SET'+str(sorted(keep+add))
|
|
return canon(l)
|
|
diffs=collections.Counter(); ex=[]
|
|
for k in set(A)|set(B):
|
|
if iscopy(k[1]) or k in old or k in new: continue
|
|
if k[1].startswith('PLACEHOLDER'): continue
|
|
a=norm(k[0],graph(k[1]),A[k]['lines']) if k in A else None; b=[canonB(k,l) for l in B[k]['lines'] if not skip.match(l)] if k in B else None
|
|
if a!=b:
|
|
cls=(A.get(k) or B.get(k))['cls']
|
|
diffs[(k[0],cls,'absent avant' if a is None else 'absent apres' if b is None else 'modifie')]+=1
|
|
if len(ex)<40: ex.append((k,[x for x in (a or []) if x not in (b or [])][:2],[x for x in (b or []) if x not in (a or [])][:2]))
|
|
print('objets en ecart hors noeuds remplaces et copies :',sum(diffs.values()))
|
|
for k,v in sorted(diffs.items()): print(' ',v,*k)
|
|
for e in ex: print(e[0]); [print(' -',x[:160]) for x in e[1]]; [print(' +',x[:160]) for x in e[2]]
|
|
def pinlinks(o,name):
|
|
for l in o['lines']:
|
|
m=re.match(r'^ pin (\S+) (\[.*\] defaut=.*) -> (.*)$',l)
|
|
if m and m.group(1)==name: return sorted(x for x in m.group(3).split(', ') if x)
|
|
return None
|
|
def pinhead(o,name):
|
|
# Categorie et valeurs par defaut de la broche (sans les liaisons).
|
|
for l in o['lines']:
|
|
m=re.match(r'^ pin (\S+) (\[.*\] defaut=.*) -> (.*)$',l)
|
|
if m and m.group(1)==name: return m.group(2)
|
|
return None
|
|
ok=bad=0
|
|
for k,v in old.items():
|
|
t=idx[(k[0],k[1].rsplit('.',1)[0],pos(v))]; n=B[t]
|
|
g=graph(k[1])
|
|
def rn(lst):
|
|
out=[]
|
|
for x in lst or []:
|
|
for (p2,gg,o),nn in ren.items():
|
|
if p2==k[0] and gg==g: x=x.replace(o+'.',nn+'.') if x.split('.')[0]==o else x
|
|
out.append(x)
|
|
return sorted(out)
|
|
same=all(rn(pinlinks(v,op))==pinlinks(n,np_) for op,np_ in PROFIL['pins'])
|
|
# Profil a broches homonymes : les valeurs par defaut doivent aussi etre reportees.
|
|
if same and all(op==np_ for op,np_ in PROFIL['pins']): same=all(pinhead(v,op)==pinhead(n,op) for op,_ in PROFIL['pins'])
|
|
if same: ok+=1
|
|
else:
|
|
bad+=1; print('ECART',k[1],[(op,pinhead(v,op),rn(pinlinks(v,op)),pinhead(n,np_),pinlinks(n,np_)) for op,np_ in PROFIL['pins']])
|
|
print('noeuds remplaces : liaisons identiques',ok,'/ ecarts',bad)
|