L'axe Z, qui sert en principe à placer la hauteur des objets, a un fonctionnement assez particulier sur ce moteur. Si j'ai à peu près suivi (et je rappelle que je ne suis pas dev, donc il va falloir vérifier), le serveur envoie des coordonnées X,Y, Z : les deux premières ne sont pas très complexes, ça place les objets sur la carte. Le Z, par contre... Attention !
Aleajactaest travaille sur la récupération de ces coordonnées pour les échanges clients/serveurs et sans grande surprise, cet axe Z se conduit d'une façon peu intuitive. Je recopie ses messages.
Citation de: Aleajactaest
Voici les deux codes incriminés. Le code côté Envoi de la position (coté client) - (j'ai viré du code pour simplifier)
// khanat-opennel-code/code/ryzom/common/src/game_share/action_position.cpp:96
void CActionPosition::pack (NLMISC::CBitMemStream &message)
{
// Get the right position, depending on the "relative" bit, and
// scale precision from 1 mm to 16 mm and take only 16 lower bits (=> 1048 m range)
uint32 pxy16;
uint16 posx16, posy16, posz16;
posx16 = (uint16)(Position[0] >> 4);
posy16 = (uint16)(Position[1] >> 4);
pxy16 = ((uint32)(posx16) << 16) | (uint32)posy16;
posz16 = ((uint16)(Position[2] >> 4) + 2) & ((uint16)0xFFFC);
if ( IsRelative ) posz16 |= (uint16)0x1;
if ( Interior ) posz16 |= (uint16)0x2;
message.serialAndLog1( pxy16 );
message.serialAndLog1( posz16 );
Le code coté VisualProperties - (j'ai viré du code pour simplifié)
// khanat-opennel-code/code/ryzom/client/src/property_decoder.cpp:73
void CPropertyDecoder::receive(TPacketNumber /* packetNumber */, CAction *action)
{
if (action->Code == ACTION_POSITION_CODE)
{
CActionPosition *act = (CActionPosition *)(action);
if ( act->IsRelative )
{
act->Position[0] = (sint32)act->Position16[0];
act->Position[1] = (sint32)act->Position16[1];
act->Position[2] = (sint32)act->Position16[2];
_Entities[act->Slot].PosIsRelative = true;
_Entities[act->Slot].PosIsInterior = false;
}
else
{
// Absolute position
decodeAbsPos2D( act->Position[0], act->Position[1], act->Position16[0], act->Position16[1] );
act->Position[2] = ((sint32)((sint16)act->Position16[2])) << 4;
if (act->Interior)
act->Position[2] += 2;
_Entities[act->Slot].PosIsRelative = false;
_Entities[act->Slot].PosIsInterior = act->Interior;
}
et le résultat dans les captures
2020/05/14 21:58:38 packet_1727 Client3 Server1 MsgXML/POSITION/X 8868703
2020/05/14 21:58:38 packet_1727 Client3 Server1 MsgXML/POSITION/Y -10595373
2020/05/14 21:58:38 packet_1727 Client3 Server1 MsgXML/POSITION/Z 5724
2020/05/14 21:58:38 packet_1727 Client3 Server1 MsgXML/POSITION/Heading -0.5890485644340515
2020/05/14 21:58:39 packet_1739 Server1 Client2 VisualProperty/Slot_184/POSITION_CODE/px 30005
2020/05/14 21:58:39 packet_1739 Server1 Client2 VisualProperty/Slot_184/POSITION_CODE/py 58685
2020/05/14 21:58:39 packet_1739 Server1 Client2 VisualProperty/Slot_184/POSITION_CODE/pz 66
2020/05/14 21:58:39 packet_1739 Server1 Client2 VisualProperty/Slot_184/POSITION_CODE/IsRelative False
2020/05/14 21:58:39 packet_1739 Server1 Client2 VisualProperty/Slot_184/POSITION_CODE/Interior True
2020/05/14 21:58:43 packet_1779 Server1 Client2 VisualProperty/Slot_184/Sint64/PROPERTY_ORIENTATION 3200265882
J'ai mis les données en bit, plus facile pour les comparaisons
2020/05/14 21:58:38 packet_1727 Client3 Server1 MsgXML/POSITION/X 00000000100001110101001101011111
2020/05/14 21:58:38 packet_1727 Client3 Server1 MsgXML/POSITION/Y 11111111010111100101001111010011
2020/05/14 21:58:38 packet_1727 Client3 Server1 MsgXML/POSITION/Z 00000000000000000001011001011100
2020/05/14 21:58:38 packet_1727 Client3 Server1 MsgXML/POSITION/Heading 10111110011101000101101110001100
2020/05/14 21:58:39 packet_1739 Server1 Client2 VisualProperty/Slot_184/POSITION_CODE/px 0111010100110101
2020/05/14 21:58:39 packet_1739 Server1 Client2 VisualProperty/Slot_184/POSITION_CODE/py 1110010100111101
2020/05/14 21:58:39 packet_1739 Server1 Client2 VisualProperty/Slot_184/POSITION_CODE/pz 0000000001000010
2020/05/14 21:58:39 packet_1739 Server1 Client2 VisualProperty/Slot_184/POSITION_CODE/IsRelative False
2020/05/14 21:58:39 packet_1739 Server1 Client2 VisualProperty/Slot_184/POSITION_CODE/Interior True
2020/05/14 21:58:43 packet_1779 Server1 Client2 VisualProperty/Slot_184/Sint64/PROPERTY_ORIENTATION 10111110110000000010111010011010
si on regarde plus finement on obtient :
X : 00000000100001110101001101011111 => xxxxxxxxxxxx0111010100110101xxxx
Y : 11111111010111100101001111010011 => xxxxxxxxxxxx1110010100111101xxxx
Z : 00000000000000000001011001011100 ?? 0000000001000010
Heading : 10111110011101000101101110001100 ==10111110110000000010111010011010
bref, on retrouve une relation entre X, Y & Heading, par contre Z (même en ajoutant +2 , cela ne marche pas)
Sachant que Liria avait pas mal épluché le sujet, et me souvenant de longues conversations autour des ponts dans Ryzom, j'ai cherché dans les vieux logs et les archives. Mais je crains que ces conversations aient eu lieu en jeu ou même en direct, je n'ai pas retrouvé les détails en rapport avec ce qui surnageait dans ma mémoire.
Je vais essayer d'expliquer ce dont je me souviens, après je colle encore quelques logs en rapport, qui donnent les pistes... encore une fois, entre ma mémoire et mes connaissances fragmentaires, ce que je dis peut être totalement faux ! mais ça fait des pistes.
<liria> l'absence d'axe Z c'est surtout que tu ne peux superposer eux chemin l'un au dessus de l'autre
<liria> sinon y 'a toujours une info Z qui est de où est le sol pour la coordonée X,Y
Lors de la génération des cartes, un certain nombre de choses vont être calculés et être fixées à ce moment. Entre autre "où est le sol" afin que les personnages puissent y marcher. Je pense que le niveau 0 de l'axe Z n'est pas absolu, mais relatif, c'est à dire : c'est au niveau de la surface du sol. Le reste se positionne par rapport à ça. À noter d'ailleurs que les collisions sont une aberration au niveau de l'axe Z, elles sont au niveau de l'infini, ce qui ne simplifie pas le fait de "sauter par dessus une barrière". Donc, en principe dans Ryzom, impossible d'avoir un chemin qui passe au dessus d'un autre, comme une route sur et sous un pont : le seul endroit où le personnage peut marcher est le point "0". Pourtant il y a quelques ponts dans Ryzom. Si on a l'occasion d'analyser ces cartes (et je crois qu'elles ne sont pas dispo dans les assets libérés), on se rend compte qu'un pont de ce genre est en réalité constitué de deux zones, et qu'on passe des sortes de portails entre elles (c'est invisible en tant que joueur, mais y'a des "trucs" sur les cartes). Ça se rapproche de ce qu'on peut croiser dans des moteurs de jeux en géométrie non euclidienne, et c'est absolument pas intuitif à comprendre. C'était cependant pas si rare à l'époque (les années 2000), visiblement le moteur de Landes Éternelles a un truc similaire.
Il est possible que la variable "Interior" soit justement utilisé pour ces hacks, c'est même assez probable. Bref, en gros, lorsqu'on est "sur" le pont, on est dans une zone, "sous" le pont dans une autre, et elles ne se chevauchent pas même si on peut visuellement voir le perso qui se ballade au dessus/dessous.
Logs qui datent de y'a longtemps ! (2013)
<liria> Lyne en générant la carte d'une région tu spécifies aussi les zones inaccessibles non traversable
<Lyne> Donc toutes les limites de pontons sont intraversables, c'est ça ?
<liria> par exemple la rembarde la falaise ou le bord du ponton...
<Lyne> D'accord
<liria> hum
<liria> d'un autre coté
<liria> on peut virer cette limite
<liria> sauf
<liria> que
<Lyne> Et je suppose qu'on ne peut pas les rendre traversable dans une seule direction ? *soupire*
<liria> vis à vis du mécanism du jeu
<liria> tu pourra aussi sortir de l'eau là
<liria> ce qui est moins logique
<Lyne> Sur un ponton, encore, s'il n'est pas trop haut, on peut se suspendre et faire un rétablissement. Sur une falaise....
<vaiatua> huhu
<liria> par défaut lors de la génération de la carte, il calcule le dénivellé entre deux points cote à cote et si la pente est torp forte
<liria> tu ne passe pas
<vaiatua> escalade rapide
<Lyne> "par défaut", "pente trop forte"... On peut l'envisager avec une pente forte vers le bas ?
<liria> non lyne
<Lyne> Dommage....
<liria> le mécanisme te dessine les surface du sol ou tu peux alle
<liria> aller*
<liria> pas un sens de passage
<vaiatua> pour l'animation escalier : si elle était implantée : elle se déclencherait seule ? comment ça se passe ?
<liria> calculer la pente c'est juste pour aider à déterminer si ce point est dans la surface atteignable
<liria> mais au final il ne garde que cette notion de surface atteignable
Osquallo a aussi travaillé sur le sujet, s'il passe, il sera le plus à même d'expliquer car il combine les connaissances du moteur de jeu et des mécanismes 3D.
L'axe Z est vraiment très particulier sur Nel. Baroque, même. Ça fait partie des trucs qui devaient avoir une bonne raison à l'époque, mais qui a créé des freins ensuite. Un des morceaux qui demanderait un dev au cœur bien accroché pour dépoussiérer la chose... et qu'on aie un axe Z qui fonctionne comme dans les jeux modernes. Cependant, ce n'est absolument pas trivial. Ce qui est souvent traduit par "une absence d'axe Z" dans les conversations ryzomiennes est une des choses qui marque le plus les joueurs de Ryzom, et comme certains d'entre eux sont dev, je suis certaine que tous ceux-là ont du regarder ça, puis repartir dans la foulée, effrayé. Il faut garder en tête que cela veut dire bidouiller des trucs qui touchent à la 3D, sujet épineux. Dans notre cas, vu qu'on part dans l'idée de virer l'actuel client 3D, il est possible que toucher à ce code soit un peu moins "gros" parce qu'on n'a pas besoin de toucher à la partie Nel... à voir.
Deed ajoute que ring/ark permet de superposer les choses, mais le fonctionnement de ces éléments est un peu différent, et on ne va pas trop s'embêter avec. Et de mémoire, on peut superposer les objets statiques (instanciés) qui ignorent les collisions, mais pas recréer des ponts/étages, où les objets mouvants (personnages, mobs) pourraient se déplacer.