чем отличается плеер от моба? правильно, ничем (объектную плеерскую надстройку не будет считать здесь). для этого юнита можно отправлять любые плеерские опкоды. можно хоть MSG_MOVE_STOP слать, с шагом 100 ярдов - и будет телепорт.
почему на мангосе и трините сделано так? я не знаю. просто тот кто это делал - сделал свою работу плохо. затычками. к другим затычкам. отсюда соответствующая репутация (не в обиду всему проекту). ну не суть. я уже забыл, но по моему у клиента есть дополнительный обработчик на телепорт. но по факту все это ерунда, нужно для правильных отрисовок да и только.
насколько я мог понять, сейчас все эти пакеты обрабатываются вообще одним обработчиком. с небольшими дополнительными "вставками" для некоторых опкодов. телепорт как раз в их числе.
изначально мув данные передавались внутри А9 и был соответствующий кейз в клиенте (стадия альфы 2004 и последующие некоторые беты). потом стали добавлять "новые фичи", связанные с мувементом, в виде новых опкодов. вполне резонно было вынести мув блок из А9 в отдельный обработчик и объеденить старые и новые опкоды. в новом варианте видимо по привычке часть данных А9 называют мувблоком, хотя формально их там давно нет, это ошибка.
один из транков моего сервера поддерживает альфу 0.5.3, что называется чисто на поржать
Код:
function msgBuild(var Buf: TSockBuffer; var m: T_SMSG_UPDATE_OBJECT): longint; overload;
begin
pkt.InitCmd(Buf, SMSG_UPDATE_OBJECT);
pkt.AddLong(Buf, m.Count); // count of objects
pkt.AddByte(Buf, m.UpdateType);
pkt.AddInt64(Buf, m.Full.GUID);
Case m.UpdateType of
UPDATE_PARTIAL:
begin
// UPDATE_PARTIAL: partial block
j:= Length(m.Full.UpdateField);
upkt.Init(j);
for i:= 0 to j-1 do
if m.Full.UpdateField[i].Added then
upkt.AddLong(i, m.Full.UpdateField[i].Value);
// UPDATE_PARTIAL: build A9
upkt.MakeUpdateBlock(@upkt_buf);
pkt.AddByte(Buf, upkt.blocks);
pkt.AddArray(Buf, @upkt_buf, upkt.data_ofs);
end;
UPDATE_MOVEMENT:
begin
pkt.AddInt64(Buf, m.Movement.TransportGUID);
pkt.AddFloat(Buf, m.Movement.TransportPosition.x);
pkt.AddFloat(Buf, m.Movement.TransportPosition.y);
pkt.AddFloat(Buf, m.Movement.TransportPosition.z);
pkt.AddFloat(Buf, m.Movement.TransportFacing);
pkt.AddFloat(Buf, m.Movement.Position.x);
pkt.AddFloat(Buf, m.Movement.Position.y);
pkt.AddFloat(Buf, m.Movement.Position.z);
pkt.AddFloat(Buf, m.Movement.Facing);
pkt.AddFloat(Buf, m.Movement.Pitch);
pkt.AddLong(Buf, m.Movement.Flags);
pkt.AddLong(Buf, m.Movement.TimeFallen);
pkt.AddFloat(Buf, m.Movement.WalkSpeed);
pkt.AddFloat(Buf, m.Movement.RunSpeed);
pkt.AddFloat(Buf, m.Movement.SwimSpeed);
pkt.AddFloat(Buf, m.Movement.TurnRate);
// moveFlags depended block here
end;
UPDATE_FULL:
begin
pkt.AddByte(Buf, m.Full.ObjectTypeID); // world object type
...
причем я не стал тут реализовывать флаги и дополнительные блоки. вломы
теперь по поводу рывков: смотреть в сторону синхронизации объектов. это довольно сложная для понимания тема и немного хитрая в реализации. боюсь не осилите снаскоку. еще никто не осилил ее ни в одном проекте (кроме одного
), даже близко не подошли. я серьезно. сплайты тут не причем, да.
насчет m_movementInfo: "просто" m_position - выкинуть, правильно - разместить в m_movementInfo, в одном месте, все правильно.
Код:
TTransportInfo = record
GUID: uInt64;
Entry: longint;
Position: C3Vector;
Facing: single;
end;
TSplineFaceData = record
spot: C3Vector;
guid: longword;
facing: single;
end;
C3Point = record
IsPathPoint: boolean;
Position: C3Vector;
end;
C3Spline_CatmullRom = record
cachedLength: single;
points: array of C3Point;
cachedSegLength: array of single;
splineMode: byte; // MODE_LINEAR = 0x0, MODE_CATMULLROM = 0x1
end;
TMoveSpline = record
flags: longword;
face: TSplineFaceData;
start: longword;
current: longword;
duration: longword;
spline: C3Spline_CatmullRom;
end;
TMovementInfo = record
m_lastNetMsgID: longword;
m_position: C3Vector;
m_prev_position: C3Vector;
m_facing: single;
m_pitch: single;
m_groundNormal: C3Vector;
m_guid: longword;
m_moveFlags: longword;
m_prev_moveFlags: longword;
m_anchorPosition: C3Vector;
m_anchorFacing: single;
m_anchorPitch: single;
m_moveStartTime: longword;
m_prev_moveStartTime: longword;
m_direction: C3Vector;
m_direction2d: C2Vector;
m_cosAnchorPitch: single;
m_sinAnchorPitch: single;
m_reDirection: C3Vector;
m_lastReDirectionSent: C3Vector;
m_fallStartTime: longword;
m_fallenTime: longword;
m_fallStartElevation: single;
m_currentSpeed: single;
m_Speed: single;
m_prev_Speed: single;
m_walkSpeed: single;
m_runSpeed: single;
m_runBackSpeed: single;
m_swimSpeed: single;
m_swimBackSpeed: single;
m_turnRate: single;
m_collisionBoxHalfDepth: single;
m_collisionBoxHeight: single;
m_stepUpHeight: single;
m_jumpVelocity: single;
m_spline: TMoveSpline;
m_waterSurfaceElev: single;
Transport: TTransportInfo;
m_timeSkipped: longword;
end;
// ===========================================================================
T_MSG_MOVE_STATE = record
GUID: longword;
MovementInfo: TMovementInfo;
end;
чем отличается плеер от юнита? правильно, ничем
мувемент у них один.