1 //**************************************************************************
2 //**
3 //** ## ## ## ## ## #### #### ### ###
4 //** ## ## ## ## ## ## ## ## ## ## #### ####
5 //** ## ## ## ## ## ## ## ## ## ## ## ## ## ##
6 //** ## ## ######## ## ## ## ## ## ## ## ### ##
7 //** ### ## ## ### ## ## ## ## ## ##
8 //** # ## ## # #### #### ## ##
9 //**
10 //** $Id: net_channel_level.cpp 3884 2008-12-01 20:47:53Z dj_jl $
11 //**
12 //** Copyright (C) 1999-2006 Jānis Legzdiņš
13 //**
14 //** This program is free software; you can redistribute it and/or
15 //** modify it under the terms of the GNU General Public License
16 //** as published by the Free Software Foundation; either version 2
17 //** of the License, or (at your option) any later version.
18 //**
19 //** This program is distributed in the hope that it will be useful,
20 //** but WITHOUT ANY WARRANTY; without even the implied warranty of
21 //** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 //** GNU General Public License for more details.
23 //**
24 //**************************************************************************
25
26 // HEADER FILES ------------------------------------------------------------
27
28 #include "gamedefs.h"
29 #include "network.h"
30 #include "cl_local.h"
31 #include "sv_local.h"
32
33 // MACROS ------------------------------------------------------------------
34
35 // TYPES -------------------------------------------------------------------
36
37 enum
38 {
39 CMD_Side,
40 CMD_Sector,
41 CMD_PolyObj,
42 CMD_StaticLight,
43 CMD_NewLevel,
44 CMD_PreRender,
45 CMD_Line,
46 CMD_CamTex,
47 CMD_LevelTrans,
48 CMD_BodyQueueTrans,
49
50 CMD_MAX
51 };
52
53 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
54
55 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
56
57 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
58
59 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
60
61 // PUBLIC DATA DEFINITIONS -------------------------------------------------
62
63 // PRIVATE DATA DEFINITIONS ------------------------------------------------
64
65 // CODE --------------------------------------------------------------------
66
67 //==========================================================================
68 //
69 // VLevelChannel::VLevelChannel
70 //
71 //==========================================================================
72
VLevelChannel(VNetConnection * AConnection,vint32 AIndex,vuint8 AOpenedLocally)73 VLevelChannel::VLevelChannel(VNetConnection* AConnection, vint32 AIndex,
74 vuint8 AOpenedLocally)
75 : VChannel(AConnection, CHANNEL_Player, AIndex, AOpenedLocally)
76 , Level(NULL)
77 , Lines(NULL)
78 , Sides(NULL)
79 , Sectors(NULL)
80 {
81 }
82
83 //==========================================================================
84 //
85 // VLevelChannel::~VLevelChannel
86 //
87 //==========================================================================
88
~VLevelChannel()89 VLevelChannel::~VLevelChannel()
90 {
91 SetLevel(NULL);
92 }
93
94 //==========================================================================
95 //
96 // VLevelChannel::SetLevel
97 //
98 //==========================================================================
99
SetLevel(VLevel * ALevel)100 void VLevelChannel::SetLevel(VLevel* ALevel)
101 {
102 guard(VLevelChannel::SetLevel);
103 if (Level)
104 {
105 delete[] Lines;
106 delete[] Sides;
107 delete[] Sectors;
108 delete[] PolyObjs;
109 Lines = NULL;
110 Sides = NULL;
111 Sectors = NULL;
112 PolyObjs = NULL;
113 CameraTextures.Clear();
114 Translations.Clear();
115 BodyQueueTrans.Clear();
116 }
117
118 Level = ALevel;
119
120 if (Level)
121 {
122 Lines = new rep_line_t[Level->NumLines];
123 memcpy(Lines, Level->BaseLines, sizeof(rep_line_t) * Level->NumLines);
124 Sides = new rep_side_t[Level->NumSides];
125 memcpy(Sides, Level->BaseSides, sizeof(rep_side_t) * Level->NumSides);
126 Sectors = new rep_sector_t[Level->NumSectors];
127 memcpy(Sectors, Level->BaseSectors, sizeof(rep_sector_t) * Level->NumSectors);
128 PolyObjs = new rep_polyobj_t[Level->NumPolyObjs];
129 memcpy(PolyObjs, Level->BasePolyObjs, sizeof(rep_polyobj_t) * Level->NumPolyObjs);
130 }
131 unguard;
132 }
133
134 //==========================================================================
135 //
136 // VLevelChannel::SendNewLevel
137 //
138 //==========================================================================
139
SendNewLevel()140 void VLevelChannel::SendNewLevel()
141 {
142 guard(VLevelChannel::SendNewLevel);
143 guardSlow(NewLevel);
144 VMessageOut Msg(this);
145 Msg.bReliable = true;
146 Msg.WriteInt(CMD_NewLevel, CMD_MAX);
147 VStr MapName = *Level->MapName;
148 Msg << svs.serverinfo << MapName;
149 Msg.WriteInt(svs.max_clients, MAXPLAYERS + 1);
150 Msg.WriteInt(deathmatch, 256);
151 SendMessage(&Msg);
152 unguardSlow;
153
154 guardSlow(StaticLights);
155 SendStaticLights();
156 unguardSlow;
157
158 guardSlow(PreRender);
159 VMessageOut Msg(this);
160 Msg.bReliable = true;
161 Msg.WriteInt(CMD_PreRender, CMD_MAX);
162 SendMessage(&Msg);
163 unguardSlow;
164 unguard;
165 }
166
167 //==========================================================================
168 //
169 // VLevelChannel::Update
170 //
171 //==========================================================================
172
Update()173 void VLevelChannel::Update()
174 {
175 guard(VLevelChannel::Update);
176 VMessageOut Msg(this);
177 Msg.bReliable = true;
178
179 for (int i = 0; i < Level->NumLines; i++)
180 {
181 line_t* Line = &Level->Lines[i];
182 //if (!Connection->SecCheckFatPVS(Line->sector))
183 // continue;
184
185 rep_line_t* RepLine = &Lines[i];
186 if (Line->alpha == RepLine->alpha)
187 continue;
188
189 Msg.WriteInt(CMD_Line, CMD_MAX);
190 Msg.WriteInt(i, Level->NumLines);
191 Msg.WriteBit(Line->alpha != RepLine->alpha);
192 if (Line->alpha != RepLine->alpha)
193 {
194 Msg << Line->alpha;
195 Msg.WriteBit(!!(Line->flags & ML_ADDITIVE));
196 RepLine->alpha = Line->alpha;
197 }
198 }
199
200 for (int i = 0; i < Level->NumSides; i++)
201 {
202 side_t* Side = &Level->Sides[i];
203 if (!Connection->SecCheckFatPVS(Side->Sector))
204 continue;
205
206 rep_side_t* RepSide = &Sides[i];
207 if (Side->TopTexture == RepSide->TopTexture &&
208 Side->BottomTexture == RepSide->BottomTexture &&
209 Side->MidTexture == RepSide->MidTexture &&
210 Side->TopTextureOffset == RepSide->TopTextureOffset &&
211 Side->BotTextureOffset == RepSide->BotTextureOffset &&
212 Side->MidTextureOffset == RepSide->MidTextureOffset &&
213 Side->TopRowOffset == RepSide->TopRowOffset &&
214 Side->BotRowOffset == RepSide->BotRowOffset &&
215 Side->MidRowOffset == RepSide->MidRowOffset &&
216 Side->Flags == RepSide->Flags &&
217 Side->Light == RepSide->Light)
218 continue;
219
220 Msg.WriteInt(CMD_Side, CMD_MAX);
221 Msg.WriteInt(i, Level->NumSides);
222 Msg.WriteBit(Side->TopTexture != RepSide->TopTexture);
223 if (Side->TopTexture != RepSide->TopTexture)
224 {
225 Msg.WriteInt(Side->TopTexture, MAX_VUINT16);
226 RepSide->TopTexture = Side->TopTexture;
227 }
228 Msg.WriteBit(Side->BottomTexture != RepSide->BottomTexture);
229 if (Side->BottomTexture != RepSide->BottomTexture)
230 {
231 Msg.WriteInt(Side->BottomTexture, MAX_VUINT16);
232 RepSide->BottomTexture = Side->BottomTexture;
233 }
234 Msg.WriteBit(Side->MidTexture != RepSide->MidTexture);
235 if (Side->MidTexture != RepSide->MidTexture)
236 {
237 Msg.WriteInt(Side->MidTexture, MAX_VUINT16);
238 RepSide->MidTexture = Side->MidTexture;
239 }
240 Msg.WriteBit(Side->TopTextureOffset != RepSide->TopTextureOffset);
241 if (Side->TopTextureOffset != RepSide->TopTextureOffset)
242 {
243 Msg << Side->TopTextureOffset;
244 RepSide->TopTextureOffset = Side->TopTextureOffset;
245 }
246 Msg.WriteBit(Side->BotTextureOffset != RepSide->BotTextureOffset);
247 if (Side->BotTextureOffset != RepSide->BotTextureOffset)
248 {
249 Msg << Side->BotTextureOffset;
250 RepSide->BotTextureOffset = Side->BotTextureOffset;
251 }
252 Msg.WriteBit(Side->MidTextureOffset != RepSide->MidTextureOffset);
253 if (Side->MidTextureOffset != RepSide->MidTextureOffset)
254 {
255 Msg << Side->MidTextureOffset;
256 RepSide->MidTextureOffset = Side->MidTextureOffset;
257 }
258 Msg.WriteBit(Side->TopRowOffset != RepSide->TopRowOffset);
259 if (Side->TopRowOffset != RepSide->TopRowOffset)
260 {
261 Msg << Side->TopRowOffset;
262 RepSide->TopRowOffset = Side->TopRowOffset;
263 }
264 Msg.WriteBit(Side->BotRowOffset != RepSide->BotRowOffset);
265 if (Side->BotRowOffset != RepSide->BotRowOffset)
266 {
267 Msg << Side->BotRowOffset;
268 RepSide->BotRowOffset = Side->BotRowOffset;
269 }
270 Msg.WriteBit(Side->MidRowOffset != RepSide->MidRowOffset);
271 if (Side->MidRowOffset != RepSide->MidRowOffset)
272 {
273 Msg << Side->MidRowOffset;
274 RepSide->MidRowOffset = Side->MidRowOffset;
275 }
276 Msg.WriteBit(Side->Flags != RepSide->Flags);
277 if (Side->Flags != RepSide->Flags)
278 {
279 Msg.WriteInt(Side->Flags, 0x000f);
280 RepSide->Flags = Side->Flags;
281 }
282 Msg.WriteBit(Side->Light != RepSide->Light);
283 if (Side->Light != RepSide->Light)
284 {
285 Msg << Side->Light;
286 RepSide->Light = Side->Light;
287 }
288 }
289
290 for (int i = 0; i < Level->NumSectors; i++)
291 {
292 sector_t* Sec = &Level->Sectors[i];
293 if (!Connection->SecCheckFatPVS(Sec) &&
294 !(Sec->SectorFlags & sector_t::SF_ExtrafloorSource) &&
295 !(Sec->SectorFlags & sector_t::SF_TransferSource))
296 continue;
297
298 VEntity* FloorSkyBox = Sec->floor.SkyBox;
299 if (FloorSkyBox && !Connection->ObjMap->CanSerialiseObject(FloorSkyBox))
300 {
301 FloorSkyBox = NULL;
302 }
303 VEntity* CeilSkyBox = Sec->ceiling.SkyBox;
304 if (CeilSkyBox && !Connection->ObjMap->CanSerialiseObject(CeilSkyBox))
305 {
306 CeilSkyBox = NULL;
307 }
308
309 rep_sector_t* RepSec = &Sectors[i];
310 bool FloorChanged = RepSec->floor_dist != Sec->floor.dist ||
311 mround(RepSec->floor_xoffs) != mround(Sec->floor.xoffs) ||
312 mround(RepSec->floor_yoffs) != mround(Sec->floor.yoffs) ||
313 RepSec->floor_XScale != Sec->floor.XScale ||
314 RepSec->floor_YScale != Sec->floor.YScale ||
315 mround(RepSec->floor_Angle) != mround(Sec->floor.Angle) ||
316 mround(RepSec->floor_BaseAngle) != mround(Sec->floor.BaseAngle) ||
317 mround(RepSec->floor_BaseYOffs) != mround(Sec->floor.BaseYOffs) ||
318 RepSec->floor_SkyBox != FloorSkyBox;
319 bool CeilChanged = RepSec->ceil_dist != Sec->ceiling.dist ||
320 mround(RepSec->ceil_xoffs) != mround(Sec->ceiling.xoffs) ||
321 mround(RepSec->ceil_yoffs) != mround(Sec->ceiling.yoffs) ||
322 RepSec->ceil_XScale != Sec->ceiling.XScale ||
323 RepSec->ceil_YScale != Sec->ceiling.YScale ||
324 mround(RepSec->ceil_Angle) != mround(Sec->ceiling.Angle) ||
325 mround(RepSec->ceil_BaseAngle) != mround(Sec->ceiling.BaseAngle) ||
326 mround(RepSec->ceil_BaseYOffs) != mround(Sec->ceiling.BaseYOffs) ||
327 RepSec->ceil_SkyBox != CeilSkyBox;
328 bool LightChanged = abs(RepSec->lightlevel - Sec->params.lightlevel) >= 4;
329 bool FadeChanged = RepSec->Fade != Sec->params.Fade;
330 bool SkyChanged = RepSec->Sky != Sec->Sky;
331 bool MirrorChanged = RepSec->floor_MirrorAlpha != Sec->floor.MirrorAlpha ||
332 RepSec->ceil_MirrorAlpha != Sec->ceiling.MirrorAlpha;
333 if (RepSec->floor_pic == Sec->floor.pic &&
334 RepSec->ceil_pic == Sec->ceiling.pic &&
335 !FloorChanged && !CeilChanged && !LightChanged && !FadeChanged &&
336 !SkyChanged && !MirrorChanged)
337 continue;
338
339 Msg.WriteInt(CMD_Sector, CMD_MAX);
340 Msg.WriteInt(i, Level->NumSectors);
341 Msg.WriteBit(RepSec->floor_pic != Sec->floor.pic);
342 if (RepSec->floor_pic != Sec->floor.pic)
343 {
344 Msg.WriteInt(Sec->floor.pic, MAX_VUINT16);
345 }
346 Msg.WriteBit(RepSec->ceil_pic != Sec->ceiling.pic);
347 if (RepSec->ceil_pic != Sec->ceiling.pic)
348 {
349 Msg.WriteInt(Sec->ceiling.pic, MAX_VUINT16);
350 }
351 Msg.WriteBit(FloorChanged);
352 if (FloorChanged)
353 {
354 Msg.WriteBit(RepSec->floor_dist != Sec->floor.dist);
355 if (RepSec->floor_dist != Sec->floor.dist)
356 {
357 Msg << Sec->floor.dist;
358 Msg << Sec->floor.TexZ;
359 }
360 Msg.WriteBit(mround(RepSec->floor_xoffs) != mround(Sec->floor.xoffs));
361 if (mround(RepSec->floor_xoffs) != mround(Sec->floor.xoffs))
362 Msg.WriteInt(mround(Sec->floor.xoffs) & 63, 64);
363 Msg.WriteBit(mround(RepSec->floor_yoffs) != mround(Sec->floor.yoffs));
364 if (mround(RepSec->floor_yoffs) != mround(Sec->floor.yoffs))
365 Msg.WriteInt(mround(Sec->floor.yoffs) & 63, 64);
366 Msg.WriteBit(RepSec->floor_XScale != Sec->floor.XScale);
367 if (RepSec->floor_XScale != Sec->floor.XScale)
368 Msg << Sec->floor.XScale;
369 Msg.WriteBit(RepSec->floor_YScale != Sec->floor.YScale);
370 if (RepSec->floor_YScale != Sec->floor.YScale)
371 Msg << Sec->floor.YScale;
372 Msg.WriteBit(mround(RepSec->floor_Angle) != mround(Sec->floor.Angle));
373 if (mround(RepSec->floor_Angle) != mround(Sec->floor.Angle))
374 Msg.WriteInt((int)AngleMod(Sec->floor.Angle), 360);
375 Msg.WriteBit(mround(RepSec->floor_BaseAngle) != mround(Sec->floor.BaseAngle));
376 if (mround(RepSec->floor_BaseAngle) != mround(Sec->floor.BaseAngle))
377 Msg.WriteInt((int)AngleMod(Sec->floor.BaseAngle), 360);
378 Msg.WriteBit(mround(RepSec->floor_BaseYOffs) != mround(Sec->floor.BaseYOffs));
379 if (mround(RepSec->floor_BaseYOffs) != mround(Sec->floor.BaseYOffs))
380 Msg.WriteInt(mround(Sec->floor.BaseYOffs) & 63, 64);
381 Msg.WriteBit(RepSec->floor_SkyBox != FloorSkyBox);
382 if (RepSec->floor_SkyBox != FloorSkyBox)
383 Msg << FloorSkyBox;
384 }
385 Msg.WriteBit(CeilChanged);
386 if (CeilChanged)
387 {
388 Msg.WriteBit(RepSec->ceil_dist != Sec->ceiling.dist);
389 if (RepSec->ceil_dist != Sec->ceiling.dist)
390 {
391 Msg << Sec->ceiling.dist;
392 Msg << Sec->ceiling.TexZ;
393 }
394 Msg.WriteBit(mround(RepSec->ceil_xoffs) != mround(Sec->ceiling.xoffs));
395 if (mround(RepSec->ceil_xoffs) != mround(Sec->ceiling.xoffs))
396 Msg.WriteInt(mround(Sec->ceiling.xoffs) & 63, 64);
397 Msg.WriteBit(mround(RepSec->ceil_yoffs) != mround(Sec->ceiling.yoffs));
398 if (mround(RepSec->ceil_yoffs) != mround(Sec->ceiling.yoffs))
399 Msg.WriteInt(mround(Sec->ceiling.yoffs) & 63, 64);
400 Msg.WriteBit(RepSec->ceil_XScale != Sec->ceiling.XScale);
401 if (RepSec->ceil_XScale != Sec->ceiling.XScale)
402 Msg << Sec->ceiling.XScale;
403 Msg.WriteBit(RepSec->ceil_YScale != Sec->ceiling.YScale);
404 if (RepSec->ceil_YScale != Sec->ceiling.YScale)
405 Msg << Sec->ceiling.YScale;
406 Msg.WriteBit(mround(RepSec->ceil_Angle) != mround(Sec->ceiling.Angle));
407 if (mround(RepSec->ceil_Angle) != mround(Sec->ceiling.Angle))
408 Msg.WriteInt((int)AngleMod(Sec->ceiling.Angle), 360);
409 Msg.WriteBit(mround(RepSec->ceil_BaseAngle) != mround(Sec->ceiling.BaseAngle));
410 if (mround(RepSec->ceil_BaseAngle) != mround(Sec->ceiling.BaseAngle))
411 Msg.WriteInt((int)AngleMod(Sec->ceiling.BaseAngle), 360);
412 Msg.WriteBit(mround(RepSec->ceil_BaseYOffs) != mround(Sec->ceiling.BaseYOffs));
413 if (mround(RepSec->ceil_BaseYOffs) != mround(Sec->ceiling.BaseYOffs))
414 Msg.WriteInt(mround(Sec->ceiling.BaseYOffs) & 63, 64);
415 Msg.WriteBit(RepSec->ceil_SkyBox != CeilSkyBox);
416 if (RepSec->ceil_SkyBox != CeilSkyBox)
417 Msg << CeilSkyBox;
418 }
419 Msg.WriteBit(LightChanged);
420 if (LightChanged)
421 {
422 Msg.WriteInt(Sec->params.lightlevel >> 2, 256);
423 }
424 Msg.WriteBit(FadeChanged);
425 if (FadeChanged)
426 {
427 Msg << Sec->params.Fade;
428 }
429 Msg.WriteBit(SkyChanged);
430 if (SkyChanged)
431 {
432 Msg.WriteInt(Sec->Sky, MAX_VUINT16);
433 }
434 Msg.WriteBit(MirrorChanged);
435 if (MirrorChanged)
436 {
437 Msg << Sec->floor.MirrorAlpha;
438 Msg << Sec->ceiling.MirrorAlpha;
439 }
440
441 RepSec->floor_pic = Sec->floor.pic;
442 RepSec->floor_dist = Sec->floor.dist;
443 RepSec->floor_xoffs = Sec->floor.xoffs;
444 RepSec->floor_yoffs = Sec->floor.yoffs;
445 RepSec->floor_XScale = Sec->floor.XScale;
446 RepSec->floor_YScale = Sec->floor.YScale;
447 RepSec->floor_Angle = Sec->floor.Angle;
448 RepSec->floor_BaseAngle = Sec->floor.BaseAngle;
449 RepSec->floor_BaseYOffs = Sec->floor.BaseYOffs;
450 RepSec->floor_SkyBox = FloorSkyBox;
451 RepSec->floor_MirrorAlpha = Sec->floor.MirrorAlpha;
452 RepSec->ceil_pic = Sec->ceiling.pic;
453 RepSec->ceil_dist = Sec->ceiling.dist;
454 RepSec->ceil_xoffs = Sec->ceiling.xoffs;
455 RepSec->ceil_yoffs = Sec->ceiling.yoffs;
456 RepSec->ceil_XScale = Sec->ceiling.XScale;
457 RepSec->ceil_YScale = Sec->ceiling.YScale;
458 RepSec->ceil_Angle = Sec->ceiling.Angle;
459 RepSec->ceil_BaseAngle = Sec->ceiling.BaseAngle;
460 RepSec->ceil_BaseYOffs = Sec->ceiling.BaseYOffs;
461 RepSec->ceil_SkyBox = CeilSkyBox;
462 RepSec->ceil_MirrorAlpha = Sec->ceiling.MirrorAlpha;
463 RepSec->lightlevel = Sec->params.lightlevel;
464 RepSec->Fade = Sec->params.Fade;
465 }
466
467 for (int i = 0; i < Level->NumPolyObjs; i++)
468 {
469 polyobj_t* Po = &Level->PolyObjs[i];
470 if (!Connection->CheckFatPVS(Po->subsector))
471 continue;
472
473 rep_polyobj_t* RepPo = &PolyObjs[i];
474 if (RepPo->startSpot.x == Po->startSpot.x &&
475 RepPo->startSpot.y == Po->startSpot.y &&
476 RepPo->angle == Po->angle)
477 continue;
478
479 Msg.WriteInt(CMD_PolyObj, CMD_MAX);
480 Msg.WriteInt(i, Level->NumPolyObjs);
481 Msg.WriteBit(RepPo->startSpot.x != Po->startSpot.x);
482 if (RepPo->startSpot.x != Po->startSpot.x)
483 {
484 Msg << Po->startSpot.x;
485 }
486 Msg.WriteBit(RepPo->startSpot.y != Po->startSpot.y);
487 if (RepPo->startSpot.y != Po->startSpot.y)
488 {
489 Msg << Po->startSpot.y;
490 }
491 Msg.WriteBit(RepPo->angle != Po->angle);
492 if (RepPo->angle != Po->angle)
493 {
494 Msg << Po->angle;
495 }
496
497 RepPo->startSpot = Po->startSpot;
498 RepPo->angle = Po->angle;
499 }
500
501 for (int i = 0; i < Level->CameraTextures.Num(); i++)
502 {
503 // Grow replication array if needed.
504 if (CameraTextures.Num() == i)
505 {
506 VCameraTextureInfo& C = CameraTextures.Alloc();
507 C.Camera = NULL;
508 C.TexNum = -1;
509 C.FOV = 0;
510 }
511
512 VCameraTextureInfo& Cam = Level->CameraTextures[i];
513 VCameraTextureInfo& RepCam = CameraTextures[i];
514 VEntity* CamEnt = Cam.Camera;
515 if (CamEnt && !Connection->ObjMap->CanSerialiseObject(CamEnt))
516 {
517 CamEnt = NULL;
518 }
519 if (CamEnt == RepCam.Camera && Cam.TexNum == RepCam.TexNum &&
520 Cam.FOV == RepCam.FOV)
521 {
522 continue;
523 }
524
525 // Send message
526 Msg.WriteInt(CMD_CamTex, CMD_MAX);
527 Msg.WriteInt(i, 0xff);
528 Connection->ObjMap->SerialiseObject(Msg, *(VObject**)&CamEnt);
529 Msg.WriteInt(Cam.TexNum, 0xffff);
530 Msg.WriteInt(Cam.FOV, 360);
531
532 // Update replication info.
533 RepCam.Camera = CamEnt;
534 RepCam.TexNum = Cam.TexNum;
535 RepCam.FOV = Cam.FOV;
536 }
537
538 for (int i = 0; i < Level->Translations.Num(); i++)
539 {
540 // Grow replication array if needed.
541 if (Translations.Num() == i)
542 {
543 Translations.Alloc();
544 }
545 if (!Level->Translations[i])
546 {
547 continue;
548 }
549 VTextureTranslation* Tr = Level->Translations[i];
550 TArray<VTextureTranslation::VTransCmd>& Rep = Translations[i];
551 bool Eq = Tr->Commands.Num() == Rep.Num();
552 if (Eq)
553 {
554 for (int j = 0; j < Rep.Num(); j++)
555 {
556 if (memcmp(&Tr->Commands[j], &Rep[j], sizeof(Rep[j])))
557 {
558 Eq = false;
559 break;
560 }
561 }
562 }
563 if (Eq)
564 {
565 continue;
566 }
567
568 // Send message
569 Msg.WriteInt(CMD_LevelTrans, CMD_MAX);
570 Msg.WriteInt(i, MAX_LEVEL_TRANSLATIONS);
571 Msg.WriteInt(Tr->Commands.Num(), 0xff);
572 Rep.SetNum(Tr->Commands.Num());
573 for (int j = 0; j < Tr->Commands.Num(); j++)
574 {
575 VTextureTranslation::VTransCmd& C = Tr->Commands[j];
576 Msg.WriteInt(C.Type, 2);
577 if (C.Type == 0)
578 {
579 Msg << C.Start << C.End << C.R1 << C.R2;
580 }
581 else if (C.Type == 1)
582 {
583 Msg << C.Start << C.End << C.R1 << C.G1 << C.B1 << C.R2 <<
584 C.G2 << C.B2;
585 }
586 Rep[j] = C;
587 }
588 }
589
590 for (int i = 0; i < Level->BodyQueueTrans.Num(); i++)
591 {
592 // Grow replication array if needed.
593 if (BodyQueueTrans.Num() == i)
594 {
595 BodyQueueTrans.Alloc().TranslStart = 0;
596 }
597 if (!Level->BodyQueueTrans[i])
598 {
599 continue;
600 }
601 VTextureTranslation* Tr = Level->BodyQueueTrans[i];
602 if (!Tr->TranslStart)
603 {
604 continue;
605 }
606 VBodyQueueTrInfo& Rep = BodyQueueTrans[i];
607 if (Tr->TranslStart == Rep.TranslStart &&
608 Tr->TranslEnd == Rep.TranslEnd && Tr->Colour == Rep.Colour)
609 {
610 continue;
611 }
612
613 // Send message
614 Msg.WriteInt(CMD_BodyQueueTrans, CMD_MAX);
615 Msg.WriteInt(i, MAX_BODY_QUEUE_TRANSLATIONS);
616 Msg << Tr->TranslStart << Tr->TranslEnd;
617 Msg.WriteInt(Tr->Colour, 0x00ffffff);
618 Rep.TranslStart = Tr->TranslStart;
619 Rep.TranslEnd = Tr->TranslEnd;
620 Rep.Colour = Tr->Colour;
621 }
622
623 if (Msg.GetNumBits())
624 {
625 SendMessage(&Msg);
626 }
627 unguard;
628 }
629
630 //==========================================================================
631 //
632 // VLevelChannel::SendStaticLights
633 //
634 //==========================================================================
635
SendStaticLights()636 void VLevelChannel::SendStaticLights()
637 {
638 guard(VLevelChannel::SendStaticLights);
639 for (int i = 0; i < Level->NumStaticLights; i++)
640 {
641 rep_light_t& L = Level->StaticLights[i];
642 VMessageOut Msg(this);
643 Msg.bReliable = true;
644 Msg.WriteInt(CMD_StaticLight, CMD_MAX);
645 Msg << L.Origin << L.Radius << L.Colour;
646 SendMessage(&Msg);
647 }
648 unguard;
649 }
650
651 //==========================================================================
652 //
653 // VLevelChannel::ParsePacket
654 //
655 //==========================================================================
656
ParsePacket(VMessageIn & Msg)657 void VLevelChannel::ParsePacket(VMessageIn& Msg)
658 {
659 guard(VLevelChannel::ParsePacket);
660 while (!Msg.AtEnd())
661 {
662 int Cmd = Msg.ReadInt(CMD_MAX);
663 switch (Cmd)
664 {
665 case CMD_Side:
666 {
667 side_t* Side = &Level->Sides[Msg.ReadInt(Level->NumSides)];
668 if (Msg.ReadBit())
669 Side->TopTexture = Msg.ReadInt(MAX_VUINT16);
670 if (Msg.ReadBit())
671 Side->BottomTexture = Msg.ReadInt(MAX_VUINT16);
672 if (Msg.ReadBit())
673 Side->MidTexture = Msg.ReadInt(MAX_VUINT16);
674 if (Msg.ReadBit())
675 Msg << Side->TopTextureOffset;
676 if (Msg.ReadBit())
677 Msg << Side->BotTextureOffset;
678 if (Msg.ReadBit())
679 Msg << Side->MidTextureOffset;
680 if (Msg.ReadBit())
681 Msg << Side->TopRowOffset;
682 if (Msg.ReadBit())
683 Msg << Side->BotRowOffset;
684 if (Msg.ReadBit())
685 Msg << Side->MidRowOffset;
686 if (Msg.ReadBit())
687 Side->Flags = Msg.ReadInt(0x000f);
688 if (Msg.ReadBit())
689 Msg << Side->Light;
690 }
691 break;
692
693 case CMD_Sector:
694 {
695 sector_t* Sec = &Level->Sectors[Msg.ReadInt(Level->NumSectors)];
696 float PrevFloorDist = Sec->floor.dist;
697 float PrevCeilDist = Sec->ceiling.dist;
698 if (Msg.ReadBit())
699 {
700 Sec->floor.pic = Msg.ReadInt(MAX_VUINT16);
701 }
702 if (Msg.ReadBit())
703 {
704 Sec->ceiling.pic = Msg.ReadInt(MAX_VUINT16);
705 }
706 if (Msg.ReadBit())
707 {
708 if (Msg.ReadBit())
709 {
710 Msg << Sec->floor.dist;
711 Msg << Sec->floor.TexZ;
712 }
713 if (Msg.ReadBit())
714 Sec->floor.xoffs = Msg.ReadInt(64);
715 if (Msg.ReadBit())
716 Sec->floor.yoffs = Msg.ReadInt(64);
717 if (Msg.ReadBit())
718 Msg << Sec->floor.XScale;
719 if (Msg.ReadBit())
720 Msg << Sec->floor.YScale;
721 if (Msg.ReadBit())
722 Sec->floor.Angle = Msg.ReadInt(360);
723 if (Msg.ReadBit())
724 Sec->floor.BaseAngle = Msg.ReadInt(360);
725 if (Msg.ReadBit())
726 Sec->floor.BaseYOffs = Msg.ReadInt(64);
727 if (Msg.ReadBit())
728 Msg << Sec->floor.SkyBox;
729 }
730 if (Msg.ReadBit())
731 {
732 if (Msg.ReadBit())
733 {
734 Msg << Sec->ceiling.dist;
735 Msg << Sec->ceiling.TexZ;
736 }
737 if (Msg.ReadBit())
738 Sec->ceiling.xoffs = Msg.ReadInt(64);
739 if (Msg.ReadBit())
740 Sec->ceiling.yoffs = Msg.ReadInt(64);
741 if (Msg.ReadBit())
742 Msg << Sec->ceiling.XScale;
743 if (Msg.ReadBit())
744 Msg << Sec->ceiling.YScale;
745 if (Msg.ReadBit())
746 Sec->ceiling.Angle = Msg.ReadInt(360);
747 if (Msg.ReadBit())
748 Sec->ceiling.BaseAngle = Msg.ReadInt(360);
749 if (Msg.ReadBit())
750 Sec->ceiling.BaseYOffs = Msg.ReadInt(64);
751 if (Msg.ReadBit())
752 Msg << Sec->ceiling.SkyBox;
753 }
754 if (Msg.ReadBit())
755 {
756 Sec->params.lightlevel = Msg.ReadInt(256) << 2;
757 }
758 if (Msg.ReadBit())
759 {
760 Msg << Sec->params.Fade;
761 }
762 if (Msg.ReadBit())
763 {
764 Sec->Sky = Msg.ReadInt(MAX_VUINT16);
765 }
766 if (Msg.ReadBit())
767 {
768 Msg << Sec->floor.MirrorAlpha;
769 Msg << Sec->ceiling.MirrorAlpha;
770 }
771 if (PrevFloorDist != Sec->floor.dist ||
772 PrevCeilDist != Sec->ceiling.dist)
773 {
774 CalcSecMinMaxs(Sec);
775 }
776 }
777 break;
778
779 case CMD_PolyObj:
780 {
781 polyobj_t* Po = &Level->PolyObjs[Msg.ReadInt(Level->NumPolyObjs)];
782 TVec Pos = Po->startSpot;
783 if (Msg.ReadBit())
784 Msg << Pos.x;
785 if (Msg.ReadBit())
786 Msg << Pos.y;
787 if (Pos != Po->startSpot)
788 {
789 Level->MovePolyobj(Po->tag, Pos.x - Po->startSpot.x,
790 Pos.y - Po->startSpot.y);
791 }
792 if (Msg.ReadBit())
793 {
794 float a;
795 Msg << a;
796 Level->RotatePolyobj(Po->tag, a - Po->angle);
797 }
798 }
799 break;
800
801 case CMD_StaticLight:
802 {
803 TVec Origin;
804 float Radius;
805 vuint32 Colour;
806 Msg << Origin << Radius << Colour;
807 Level->RenderData->AddStaticLight(Origin, Radius, Colour);
808 }
809 break;
810
811 case CMD_NewLevel:
812 #ifdef CLIENT
813 CL_ParseServerInfo(Msg);
814 #endif
815 break;
816
817 case CMD_PreRender:
818 Level->RenderData->PreRender();
819 #ifdef CLIENT
820 if (cls.signon)
821 {
822 Host_Error("Spawn command already sent");
823 }
824 if (!UserInfoSent)
825 {
826 cl->eventServerSetUserInfo(cls.userinfo);
827 UserInfoSent = true;
828 }
829 #endif
830 Connection->SendCommand("PreSpawn\n");
831 GCmdBuf << "HideConsole\n";
832 break;
833
834 case CMD_Line:
835 {
836 line_t* Line = &Level->Lines[Msg.ReadInt(Level->NumLines)];
837 if (Msg.ReadBit())
838 {
839 Msg << Line->alpha;
840 if (Msg.ReadBit())
841 {
842 Line->flags |= ML_ADDITIVE;
843 }
844 else
845 {
846 Line->flags &= ~ML_ADDITIVE;
847 }
848 }
849 }
850 break;
851
852 case CMD_CamTex:
853 {
854 int i = Msg.ReadInt(0xff);
855 while (Level->CameraTextures.Num() <= i)
856 {
857 VCameraTextureInfo& C = Level->CameraTextures.Alloc();
858 C.Camera = NULL;
859 C.TexNum = -1;
860 C.FOV = 0;
861 }
862 VCameraTextureInfo& Cam = Level->CameraTextures[i];
863 Connection->ObjMap->SerialiseObject(Msg, *(VObject**)&Cam.Camera);
864 Cam.TexNum = Msg.ReadInt(0xffff);
865 Cam.FOV = Msg.ReadInt(360);
866 }
867 break;
868
869 case CMD_LevelTrans:
870 {
871 int i = Msg.ReadInt(MAX_LEVEL_TRANSLATIONS);
872 while (Level->Translations.Num() <= i)
873 {
874 Level->Translations.Append(NULL);
875 }
876 VTextureTranslation* Tr = Level->Translations[i];
877 if (!Tr)
878 {
879 Tr = new VTextureTranslation;
880 Level->Translations[i] = Tr;
881 }
882 Tr->Clear();
883 int Count = Msg.ReadInt(0xff);
884 for (int j = 0; j < Count; j++)
885 {
886 vuint8 Type = Msg.ReadInt(2);
887 if (Type == 0)
888 {
889 vuint8 Start;
890 vuint8 End;
891 vuint8 SrcStart;
892 vuint8 SrcEnd;
893 Msg << Start << End << SrcStart << SrcEnd;
894 Tr->MapToRange(Start, End, SrcStart, SrcEnd);
895 }
896 else if (Type == 1)
897 {
898 vuint8 Start;
899 vuint8 End;
900 vuint8 R1;
901 vuint8 G1;
902 vuint8 B1;
903 vuint8 R2;
904 vuint8 G2;
905 vuint8 B2;
906 Msg << Start << End << R1 << G1 << B1 << R2 << G2 << B2;
907 Tr->MapToColours(Start, End, R1, G1, B1, R2, G2, B2);
908 }
909 }
910 }
911 break;
912
913 case CMD_BodyQueueTrans:
914 {
915 int i = Msg.ReadInt(MAX_BODY_QUEUE_TRANSLATIONS);
916 while (Level->BodyQueueTrans.Num() <= i)
917 {
918 Level->BodyQueueTrans.Append(NULL);
919 }
920 VTextureTranslation* Tr = Level->BodyQueueTrans[i];
921 if (!Tr)
922 {
923 Tr = new VTextureTranslation;
924 Level->BodyQueueTrans[i] = Tr;
925 }
926 Tr->Clear();
927 vuint8 TrStart;
928 vuint8 TrEnd;
929 Msg << TrStart << TrEnd;
930 vint32 Col = Msg.ReadInt(0x00ffffff);
931 Tr->BuildPlayerTrans(TrStart, TrEnd, Col);
932 }
933 break;
934
935 default:
936 Sys_Error("Invalid level update command %d", Cmd);
937 }
938 }
939 unguard;
940 }
941