Rivage brise : SQL de placement genere (593 creatures, 59 objets, 180 chemins)
NON APPLIQUE au serveur. Le fichier est verse pour relecture. Transpose depuis le dump world de dufernst/LegionCore-7.3.5 vers notre schema. Le generateur est pilote par les NOMS de colonnes et s arrete plutot que de produire un decalage silencieux si un schema bouge. CONTENU 593 creatures, 59 objets, 180 chemins (1495 points). Les 180 creatures a MovementType=2 ont TOUTES leur chemin : aucune orpheline. DECISIONS etablies sur donnees spawnMask 4096 = 2^12 -> spawnDifficulties '12', la difficulte 12 etant « Normal Scenario » d apres Difficulty.db2 du build 7.3.5.26972. GUID renumerotes a partir de 290100000 et 210200000, au-dessus de nos maxima 290000114 et 210120986. PhaseId : chaine vide cote reference -> 0 chez nous (colonne entiere). VALIDATION faite dans une base jetable, pas sur dc_world : import reussi, comptages exacts, et cinq controles a zero -- aucune creature hors carte, aucune difficulte erronee, aucune mobile sans chemin, aucun chemin orphelin, aucune position nulle. Aucune collision de GUID avec la base reelle. La carte 1666 y est actuellement vide, donc le DELETE d en-tete n efface rien. Repartition en altitude coherente : 454 creatures au sol, 64 au-dessus de 600 (aeronefs presumes, a confirmer en jeu). ABANDONNE faute d equivalent : npcflag2, AiID, MovementID, MeleeID, isActive, skipClone, personal_size, isTeemingSpawn. 12 creatures portaient AiID=7424 : leur comportement est perdu et reste a refaire. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,215 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Genere le SQL de placement de la carte 1666 dans NOTRE schema.
|
||||
N'applique rien : ecrit un fichier.
|
||||
|
||||
La correspondance est pilotee par les NOMS de colonnes, pas par leur
|
||||
position : si les schemas bougent, le generateur ne produira pas de
|
||||
decalage silencieux -- il s'arretera.
|
||||
"""
|
||||
import io, re, sys
|
||||
from collections import Counter
|
||||
|
||||
DUMP = '/home/ubuntu/tmp/abs/LegionCore_world_2020_04_25.sql'
|
||||
SORTIE = '/home/ubuntu/DestinyCore/sql/sylvania/rivage_brise_placements.sql'
|
||||
|
||||
GUID_CREA = 290100000
|
||||
GUID_GO = 210200000
|
||||
|
||||
NOS_CREA = ['guid','id','map','zoneId','areaId','spawnDifficulties','phaseUseFlags','PhaseId',
|
||||
'PhaseGroup','terrainSwapMap','modelid','equipment_id','position_x','position_y',
|
||||
'position_z','orientation','spawntimesecs','spawndist','currentwaypoint','curhealth',
|
||||
'curmana','MovementType','npcflag','unit_flags','unit_flags2','unit_flags3',
|
||||
'dynamicflags','ScriptName','movementmode','VerifiedBuild']
|
||||
|
||||
NOS_GO = ['guid','id','map','zoneId','areaId','spawnDifficulties','phaseUseFlags','PhaseId',
|
||||
'PhaseGroup','terrainSwapMap','position_x','position_y','position_z','orientation',
|
||||
'rotation0','rotation1','rotation2','rotation3','spawntimesecs','animprogress','state',
|
||||
'isActive','ScriptName','VerifiedBuild']
|
||||
|
||||
NOS_WP = ['id','point','position_x','position_y','position_z','orientation','delay',
|
||||
'move_type','action','action_chance','wpguid']
|
||||
|
||||
# valeurs imposees, quelle que soit la reference
|
||||
FIXES = {
|
||||
'spawnDifficulties': "'12'", # 4096 = 2^12, difficulte « Normal Scenario »
|
||||
'phaseUseFlags': '0',
|
||||
'PhaseGroup': '0',
|
||||
'terrainSwapMap': '-1',
|
||||
'unit_flags2': '0',
|
||||
'ScriptName': "''",
|
||||
'movementmode': '0',
|
||||
'VerifiedBuild': '0',
|
||||
'wpguid': '0',
|
||||
}
|
||||
|
||||
# nos colonnes qui portent un autre nom dans la reference
|
||||
ALIAS = {'move_type': 'move_flag'}
|
||||
|
||||
|
||||
def decoupe_tuples(bloc):
|
||||
res, cur, prof, chaine, echap = [], [], 0, False, False
|
||||
for c in bloc:
|
||||
if chaine:
|
||||
cur.append(c)
|
||||
if echap: echap = False
|
||||
elif c == '\\': echap = True
|
||||
elif c == "'": chaine = False
|
||||
continue
|
||||
if c == "'":
|
||||
chaine = True; cur.append(c)
|
||||
elif c == '(':
|
||||
prof += 1
|
||||
cur = [] if prof == 1 else cur + [c]
|
||||
elif c == ')':
|
||||
prof -= 1
|
||||
if prof == 0: res.append(''.join(cur))
|
||||
else: cur.append(c)
|
||||
elif prof > 0:
|
||||
cur.append(c)
|
||||
return res
|
||||
|
||||
|
||||
def champs(t):
|
||||
vals, cur, chaine, echap = [], [], False, False
|
||||
for c in t:
|
||||
if chaine:
|
||||
cur.append(c)
|
||||
if echap: echap = False
|
||||
elif c == '\\': echap = True
|
||||
elif c == "'": chaine = False
|
||||
continue
|
||||
if c == "'":
|
||||
chaine = True; cur.append(c)
|
||||
elif c == ',':
|
||||
vals.append(''.join(cur).strip()); cur = []
|
||||
else:
|
||||
cur.append(c)
|
||||
vals.append(''.join(cur).strip())
|
||||
return vals
|
||||
|
||||
|
||||
def lire(tables):
|
||||
"""Renvoie {table: (colonnes, [tuples decoupes])} pour tout le dump."""
|
||||
motif = re.compile(r"insert\s+into\s+`(%s)`\(([^)]*)\)\s+values\s*" % '|'.join(tables), re.I)
|
||||
out = {t: {'cols': None, 'rows': []} for t in tables}
|
||||
with io.open(DUMP, encoding='utf-8', errors='replace') as f:
|
||||
ligne = f.readline()
|
||||
while ligne:
|
||||
m = motif.match(ligne.lstrip())
|
||||
if not m:
|
||||
ligne = f.readline(); continue
|
||||
table = m.group(1).lower()
|
||||
cols = [c.strip().strip('`') for c in m.group(2).split(',')]
|
||||
morceaux = [ligne[ligne.lower().find('values') + 6:]]
|
||||
while not morceaux[-1].rstrip().endswith(';'):
|
||||
s = f.readline()
|
||||
if not s: break
|
||||
morceaux.append(s)
|
||||
out[table]['cols'] = cols
|
||||
for t in decoupe_tuples(''.join(morceaux)):
|
||||
v = champs(t)
|
||||
if len(v) == len(cols):
|
||||
out[table]['rows'].append(v)
|
||||
ligne = f.readline()
|
||||
return out
|
||||
|
||||
|
||||
def valeur(nom, cols, v, guid_neuf):
|
||||
if nom == 'guid':
|
||||
return str(guid_neuf)
|
||||
if nom in FIXES:
|
||||
return FIXES[nom]
|
||||
src = ALIAS.get(nom, nom)
|
||||
if src not in cols:
|
||||
raise KeyError("colonne '%s' absente de la reference" % src)
|
||||
brut = v[cols.index(src)]
|
||||
if nom in ('PhaseId', 'PhaseGroup'): # chaine cote reference, entier chez nous
|
||||
b = brut.strip().strip("'")
|
||||
return b if b else '0'
|
||||
return brut
|
||||
|
||||
|
||||
print('lecture du dump...')
|
||||
d = lire(['creature', 'gameobject', 'waypoint_data'])
|
||||
|
||||
crea = [v for v in d['creature']['rows'] if v[d['creature']['cols'].index('map')] == '1666']
|
||||
go = [v for v in d['gameobject']['rows'] if v[d['gameobject']['cols'].index('map')] == '1666']
|
||||
print('creatures 1666 : %d | objets 1666 : %d' % (len(crea), len(go)))
|
||||
assert crea and go, 'extraction vide -- refuser de generer'
|
||||
|
||||
# renumerotation, en gardant la trace ancien -> nouveau
|
||||
i_guid_c = d['creature']['cols'].index('guid')
|
||||
map_guid = {}
|
||||
for n, v in enumerate(crea):
|
||||
map_guid[v[i_guid_c]] = GUID_CREA + n
|
||||
|
||||
# chemins des creatures mobiles
|
||||
i_mt = d['creature']['cols'].index('MovementType')
|
||||
mobiles = {v[i_guid_c] for v in crea if v[i_mt] == '2'}
|
||||
wp_cols = d['waypoint_data']['cols']
|
||||
i_wid = wp_cols.index('id')
|
||||
wp = [v for v in d['waypoint_data']['rows'] if v[i_wid] in mobiles]
|
||||
chemins = len({v[i_wid] for v in wp})
|
||||
print('creatures mobiles : %d | chemins trouves : %d | points : %d' % (len(mobiles), chemins, len(wp)))
|
||||
|
||||
lignes = []
|
||||
A = lignes.append
|
||||
A("-- =====================================================================")
|
||||
A("-- Assaut du Rivage brise (carte 1666) -- PLACEMENTS")
|
||||
A("--")
|
||||
A("-- Transpose depuis le dump world de dufernst/LegionCore-7.3.5, meme")
|
||||
A("-- lignee uwow que notre fork. Les deux schemas divergent : la")
|
||||
A("-- correspondance ci-dessous est pilotee par les NOMS de colonnes, et le")
|
||||
A("-- generateur s'arrete plutot que de produire un decalage silencieux.")
|
||||
A("--")
|
||||
A("-- DECISIONS, etablies sur donnees et non supposees :")
|
||||
A("-- spawnMask 4096 = 2^12 -> spawnDifficulties '12', la difficulte 12")
|
||||
A("-- etant « Normal Scenario » d'apres Difficulty.db2 du build")
|
||||
A("-- 7.3.5.26972 (type instance 5, 5 joueurs).")
|
||||
A("-- GUID renumerotes a partir de %d (creatures) et %d (objets)," % (GUID_CREA, GUID_GO))
|
||||
A("-- au-dessus de nos maxima 290000114 et 210120986.")
|
||||
A("-- PhaseId : chaine vide cote reference -> 0 chez nous (entier).")
|
||||
A("--")
|
||||
A("-- ABANDONNE faute d'equivalent : npcflag2, AiID, MovementID, MeleeID,")
|
||||
A("-- isActive (creature), skipClone, personal_size, isTeemingSpawn.")
|
||||
A("-- 12 creatures portaient AiID=7424, une table d'IA propre au coeur de")
|
||||
A("-- reference : leur comportement est PERDU et reste a refaire.")
|
||||
A("--")
|
||||
A("-- Contenu : %d creatures, %d objets, %d chemins (%d points)." % (len(crea), len(go), chemins, len(wp)))
|
||||
A("-- =====================================================================")
|
||||
A("")
|
||||
A("DELETE FROM `creature` WHERE `map`=1666;")
|
||||
A("DELETE FROM `gameobject` WHERE `map`=1666;")
|
||||
A("DELETE FROM `waypoint_data` WHERE `id` BETWEEN %d AND %d;" % (GUID_CREA, GUID_CREA + len(crea)))
|
||||
A("")
|
||||
|
||||
A("INSERT INTO `creature` (%s) VALUES" % ','.join('`%s`' % c for c in NOS_CREA))
|
||||
bouts = []
|
||||
for n, v in enumerate(crea):
|
||||
bouts.append('(' + ','.join(valeur(c, d['creature']['cols'], v, GUID_CREA + n) for c in NOS_CREA) + ')')
|
||||
A(',\n'.join(bouts) + ';')
|
||||
A("")
|
||||
|
||||
A("INSERT INTO `gameobject` (%s) VALUES" % ','.join('`%s`' % c for c in NOS_GO))
|
||||
bouts = []
|
||||
for n, v in enumerate(go):
|
||||
bouts.append('(' + ','.join(valeur(c, d['gameobject']['cols'], v, GUID_GO + n) for c in NOS_GO) + ')')
|
||||
A(',\n'.join(bouts) + ';')
|
||||
A("")
|
||||
|
||||
if wp:
|
||||
A("INSERT INTO `waypoint_data` (%s) VALUES" % ','.join('`%s`' % c for c in NOS_WP))
|
||||
bouts = []
|
||||
for v in wp:
|
||||
anc = v[i_wid]
|
||||
ligne_vals = []
|
||||
for c in NOS_WP:
|
||||
if c == 'id':
|
||||
ligne_vals.append(str(map_guid[anc]))
|
||||
else:
|
||||
ligne_vals.append(valeur(c, wp_cols, v, 0))
|
||||
bouts.append('(' + ','.join(ligne_vals) + ')')
|
||||
A(',\n'.join(bouts) + ';')
|
||||
|
||||
io.open(SORTIE, 'w', encoding='utf-8').write('\n'.join(lignes) + '\n')
|
||||
print('ecrit : %s' % SORTIE)
|
||||
Reference in New Issue
Block a user