• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

polserver / polserver / 24035539233

06 Apr 2026 02:21PM UTC coverage: 60.76% (+0.06%) from 60.696%
24035539233

push

github

web-flow
using fmt instead of ostringstream (#873)

* using fmt instead of ostringstream

misc cleanup

* missing external libs for clang tidy check

* added test for cprops ignore while stacking
door descriptor

* use contains instead of count, removed disabled ancient code

* pack/packonto simplification/speedup

instead of using ostream and convert to string, use format and directly
a string

90 of 141 new or added lines in 17 files covered. (63.83%)

17 existing lines in 10 files now uncovered.

44503 of 73244 relevant lines covered (60.76%)

514255.82 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

18.81
/pol-core/pol/miscmsg.cpp
1
/** @file
2
 *
3
 * @par History
4
 * - 2005/11/25 MuadDib:   Added PKTBI_BF::TYPE_SESPAM: to do away with spam.
5
 * - 2005/11/23 MuadDib:   Altered handle_mode_set for 0x72 Packet. Nows reads
6
 *                         from combat.cfg for warmode_wait object. Sends the
7
 *                         0x77 Packet and returns 0 when out of timer.
8
 * - 2005/12/09 MuadDib:   Added TYPE_CLIENT_LANGUAGE for setting member uclang.
9
 * - 2006/05/24 Shinigami: Added PKTBI_BF::TYPE_CHARACTER_RACE_CHANGER to support Elfs
10
 * - 2006/05/30 Shinigami: Changed params of character_race_changer_handler()
11
 * - 2009/07/23 MuadDib:   updates for new Enum::Packet IDs
12
 * - 2009/08/14 Turley:    Added PKTBI_BF::TYPE_SCREEN_SIZE & TYPE_CLOSED_STATUS_GUMP (anti spam)
13
 * - 2009/09/03 MuadDib:   Relocation of account related cpp/h
14
 * - 2009/09/03 MuadDib:   Relocation of multi related cpp/h
15
 * - 2009/09/06 Turley:    Changed Version checks to bitfield client->ClientType
16
 *                         Added 0xE1 packet (UO3D clienttype packet)
17
 * - 2009/11/19 Turley:    ssopt.core_sends_season & .core_handled_tags - Tomi
18
 * - 2009/12/03 Turley:    toggle gargoyle flying support
19
 */
20

21

22
/* MISCMSG.CPP: Miscellaneous message handlers.  Handlers shouldn't stay here long,
23
   only until they find a better home - but this is better than putting them in POL.CPP. */
24

25
#include <algorithm>
26
#include <cstddef>
27
#include <ctype.h>
28
#include <iterator>
29
#include <string>
30

31
#include "../bscript/eprog.h"
32
#include "../bscript/impstr.h"
33
#include "../clib/clib_endian.h"
34
#include "../clib/fdump.h"
35
#include "../clib/logfacility.h"
36
#include "../clib/rawtypes.h"
37
#include "../clib/refptr.h"
38
#include "../plib/systemstate.h"
39
#include "../plib/uconst.h"
40
#include "accounts/account.h"
41
#include "cmbtcfg.h"
42
#include "fnsearch.h"
43
#include "gameclck.h"
44
#include "globals/settings.h"
45
#include "globals/uvars.h"
46
#include "guilds.h"
47
#include "mobile/attribute.h"
48
#include "mobile/charactr.h"
49
#include "module/uomod.h"
50
#include "multi/customhouses.h"
51
#include "multi/multi.h"
52
#include "network/cgdata.h"
53
#include "network/client.h"
54
#include "network/clientio.h"
55
#include "network/packethelper.h"
56
#include "network/packets.h"
57
#include "network/pktboth.h"
58
#include "network/pktdef.h"
59
#include "network/pktin.h"
60
#include "network/sockio.h"
61
#include "party.h"
62
#include "polclass.h"
63
#include "realms/realm.h"
64
#include "scrstore.h"
65
#include "spells.h"
66
#include "systems/suspiciousacts.h"
67
#include "tooltips.h"
68
#include "ufunc.h"
69
#include "uobject.h"
70
#include "uoexec.h"
71
#include "uoscrobj.h"
72

73

74
namespace Pol
75
{
76
namespace Module
77
{
78
void character_race_changer_handler( Network::Client* client, Core::PKTBI_BF* msg );
79
}
80
namespace Core
81
{
82
using namespace Network;
83

84
void handle_unknown_packet( Network::ThreadedClient* session );
85
void handle_unknown_packet( Network::Client* client )
×
86
{
87
  handle_unknown_packet( client->session() );
×
88
}
×
89

90
void party_cmd_handler( Client* client, PKTBI_BF* msg );
91

92
void OnGuildButton( Client* client );
93
void OnQuestButton( Client* client );
94
void OnChatButton( Client* client );
95

96
void handle_bulletin_boards( Client* client, PKTBI_71* /*msg*/ )
×
97
{
98
  handle_unknown_packet( client );
×
99
}
×
100

101
void handle_mode_set( Client* client, PKTBI_72* msg )
×
102
{
103
  if ( client->chr->warmode_wait > read_gameclock() )
×
104
  {
105
    send_move( client, client->chr );
×
106
    return;
×
107
  }
108

109
  client->chr->warmode_wait = read_gameclock() + settingsManager.combat_config.warmode_delay;
×
110

111

112
  bool msg_warmode = msg->warmode ? true : false;
×
113

114
  // FIXME: Should reply with 0x77 packet!? (so says various docs!) [TJ]
115
  transmit( client, msg, sizeof *msg );
×
116

117
  client->chr->set_warmode( msg_warmode );
×
118
}
119

120
void handle_keep_alive( Network::Client* client, PKTBI_73* msg )
4✔
121
{
122
  transmit( client, msg, sizeof *msg );
4✔
123
}
4✔
124

125
void handle_rename_char( Client* client, PKTIN_75* msg )
×
126
{
127
  Mobile::Character* chr = find_character( cfBEu32( msg->serial ) );
×
128
  if ( chr != nullptr )
×
129
  {
130
    if ( client->chr->can_rename( chr ) )
×
131
    {
132
      msg->name[sizeof msg->name - 1] = '\0';
×
133
      // check for legal characters
134
      for ( char* p = msg->name; *p; p++ )
×
135
      {
136
        // only allow: a-z, A-Z & spaces
137
        if ( *p != ' ' && !isalpha( *p ) )
×
138
        {
139
          std::string tmp = fmt::format(
140
              "Client#{} (account {}) attempted an invalid rename (packet {:#x}):\n{}",
141
              client->instance_, ( client->acct != nullptr ) ? client->acct->name() : "unknown",
×
142
              (int)msg->msgtype, msg->name );
×
143
          Clib::fdump( std::back_inserter( tmp ), msg->name,
×
144
                       static_cast<int>( strlen( msg->name ) ) );
×
145
          POLLOG_INFOLN( tmp );
×
146
          *p = '\0';
×
147
          send_sysmessage( client, "Invalid name!" );
×
148
          return;  // dave 12/26 if invalid name, do not apply to chr!
×
149
        }
×
150
      }
151
      chr->setname( msg->name );
×
152
    }
153
    else
154
    {
155
      send_sysmessage( client, "I can't rename that." );
×
156
    }
157
  }
158
  else
159
  {
160
    send_sysmessage( client, "I can't find that." );
×
161
  }
162
}
163

164
void handle_msg_B5( Client* client, PKTIN_B5* /*msg*/ )
×
165
{
166
  OnChatButton( client );
×
167
}
×
168

169
void handle_char_profile_request( Client* client, PKTBI_B8_IN* msg )
×
170
{
171
  ref_ptr<Bscript::EScriptProgram> prog =
172
      find_script( "misc/charprofile", true, Plib::systemstate.config.cache_interactive_scripts );
×
173
  if ( prog.get() != nullptr )
×
174
  {
175
    Mobile::Character* mobile;
176

177
    if ( msg->mode == msg->MODE_REQUEST )
×
178
    {
179
      mobile = system_find_mobile( cfBEu32( msg->profile_request.serial ) );
×
180
      if ( mobile == nullptr )
×
181
        return;
×
182
      client->chr->start_script( prog.get(), false, new Module::ECharacterRefObjImp( mobile ),
×
183
                                 new Bscript::BLong( msg->mode ), new Bscript::BLong( 0 ) );
×
184
    }
185
    else if ( msg->mode == msg->MODE_UPDATE )
×
186
    {
187
      mobile = system_find_mobile( cfBEu32( msg->profile_update.serial ) );
×
188
      if ( mobile == nullptr )
×
189
        return;
×
190
      u16* themsg = msg->profile_update.wtext;
×
191
      int intextlen = ( cfBEu16( msg->msglen ) - 12 ) / sizeof( msg->profile_update.wtext[0] );
×
192

193
      if ( intextlen < 0 )
×
194
        intextlen = 0;
×
195
      if ( intextlen > SPEECH_MAX_LEN )
×
196
        intextlen = SPEECH_MAX_LEN;
×
197
      std::string text = Bscript::String::fromUTF16( themsg, intextlen, true );
×
198
      client->chr->start_script( prog.get(), false, new Module::ECharacterRefObjImp( mobile ),
×
199
                                 new Bscript::BLong( msg->mode ), new Bscript::String( text ) );
×
200
    }
×
201
  }
202
}
×
203

204
void handle_msg_BB( Client* client, PKTBI_BB* /*msg*/ )
×
205
{
206
  handle_unknown_packet( client );
×
207
}
×
208

209
void handle_client_version( Client* client, PKTBI_BD* msg )
2✔
210
{
211
  u16 len = cfBEu16( msg->msglen ) - 3;
2✔
212
  if ( len < 100 )
2✔
213
  {
214
    int c = 0;
2✔
215
    char ch;
216
    std::string ver2 = "";
2✔
217
    while ( c < len )
16✔
218
    {
219
      ch = msg->version[c];
16✔
220
      if ( ch == 0 )
16✔
221
        break;  // seems to be null-terminated
2✔
222
      ver2 += ch;
14✔
223
      ++c;
14✔
224
    }
225
    client->setversion( ver2 );
2✔
226

227
    VersionDetailStruct vers_det;
228
    client->itemizeclientversion( ver2, vers_det );
2✔
229
    client->setversiondetail( vers_det );
2✔
230

231
    if ( client->compareVersion( CLIENT_VER_70331 ) )
2✔
232
      client->setClientType( CLIENTTYPE_70331 );
×
233
    else if ( client->compareVersion( CLIENT_VER_70300 ) )
2✔
234
      client->setClientType( CLIENTTYPE_70300 );
×
235
    else if ( client->compareVersion( CLIENT_VER_70130 ) )
2✔
236
      client->setClientType( CLIENTTYPE_70130 );
×
237
    else if ( client->compareVersion( CLIENT_VER_7090 ) )
2✔
238
      client->setClientType( CLIENTTYPE_7090 );
2✔
239
    else if ( client->compareVersion( CLIENT_VER_7000 ) )
×
240
      client->setClientType( CLIENTTYPE_7000 );
×
241
    else if ( client->compareVersion( CLIENT_VER_60142 ) )
×
242
      client->setClientType( CLIENTTYPE_60142 );
×
243
    else if ( client->compareVersion( CLIENT_VER_6017 ) )  // Grid-loc support
×
244
      client->setClientType( CLIENTTYPE_6017 );
×
245
    else if ( client->compareVersion( CLIENT_VER_5020 ) )
×
246
      client->setClientType( CLIENTTYPE_5020 );
×
247
    else if ( client->compareVersion( CLIENT_VER_5000 ) )
×
248
      client->setClientType( CLIENTTYPE_5000 );
×
249
    else if ( client->compareVersion( CLIENT_VER_4070 ) )
×
250
      client->setClientType( CLIENTTYPE_4070 );
×
251
    else if ( client->compareVersion( CLIENT_VER_4000 ) )
×
252
      client->setClientType( CLIENTTYPE_4000 );
×
253

254
    if ( settingsManager.ssopt.core_sends_season )
2✔
255
      send_season_info(
2✔
256
          client );  // Scott 10/11/2007 added for login fixes and handling 1.x clients.
257
                     // Season info needs to check client version to keep from crashing 1.x
258
                     // version not set until shortly after login complete.
259
    // send_feature_enable(client); //dave commented out 8/21/03, unexpected problems with people
260
    // sending B9 via script with this too.
261
    if ( client->acctSupports( Plib::ExpansionVersion::AOS ) )
2✔
262
    {
263
      send_object_cache( client, client->chr );
2✔
264
    }
265
  }
2✔
266
  else
267
  {
268
    POLLOG_INFOLN( "Suspect string length in PKTBI_BD packet: {}", len );
×
269
  }
270
}
2✔
271

272
void ext_stats_in( Client* client, PKTBI_BF* msg )
×
273
{
274
  if ( settingsManager.ssopt.core_handled_locks )
×
275
  {
276
    const Mobile::Attribute* attrib = nullptr;
×
277
    switch ( msg->extstatin.stat )
×
278
    {
279
    case PKTBI_BF_1A::STAT_STR:
×
280
      attrib = gamestate.pAttrStrength;
×
281
      break;
×
282
    case PKTBI_BF_1A::STAT_DEX:
×
283
      attrib = gamestate.pAttrDexterity;
×
284
      break;
×
285
    case PKTBI_BF_1A::STAT_INT:
×
286
      attrib = gamestate.pAttrIntelligence;
×
287
      break;
×
288
    default:  // sent an illegal stat. Should report to console?
×
289
      return;
×
290
    }
291

292
    if ( attrib == nullptr )  // there's no attribute for this (?)
×
293
      return;
×
294

295
    u8 state = msg->extstatin.mode;
×
296
    if ( state > 2 )  // FIXME hard-coded value
×
297
      return;
×
298

299
    client->chr->attribute( attrib->attrid ).lock( state );
×
300
  }
301
}
302

303
void handle_msg_BF( Client* client, PKTBI_BF* msg )
8✔
304
{
305
  UObject* obj = nullptr;
8✔
306
  Multi::UMulti* multi = nullptr;
8✔
307
  Multi::UHouse* house = nullptr;
8✔
308
  switch ( cfBEu16( msg->subcmd ) )
8✔
309
  {
310
  case PKTBI_BF::TYPE_CLIENT_LANGUAGE:
2✔
311
    client->chr->uclang = Clib::strlowerASCII( msg->client_lang );
2✔
312
    break;
2✔
313
  case PKTBI_BF::TYPE_REQ_FULL_CUSTOM_HOUSE:
×
314
    if ( !client->acctSupports( Plib::ExpansionVersion::AOS ) )
×
315
      return;
×
316
    multi = system_find_multi( cfBEu32( msg->reqfullcustomhouse.house_serial ) );
×
317
    if ( multi != nullptr )
×
318
    {
319
      house = multi->as_house();
×
320
      if ( house != nullptr )
×
321
      {
322
        if ( client->acctSupports( Plib::ExpansionVersion::AOS ) )
×
323
        {
324
          send_object_cache( client, (UObject*)( house ) );
×
325
        }
326
        // consider sending working design to certain players, to assist building, or GM help
327
        CustomHousesSendFull( house, client, Multi::HOUSE_DESIGN_CURRENT );
×
328
      }
329
    }
330
    break;
×
331
  case PKTBI_BF::TYPE_OBJECT_CACHE:
1✔
332
    if ( !client->acctSupports( Plib::ExpansionVersion::AOS ) )
1✔
333
      return;
×
334
    obj = system_find_object( cfBEu32( msg->objectcache.serial ) );
1✔
335
    if ( obj != nullptr )
1✔
336
    {
337
      SendAOSTooltip( client, obj );
1✔
338
    }
339
    break;
1✔
340
  case PKTBI_BF::TYPE_SESPAM:
×
341
    return;
×
342
    break;
343
  case PKTBI_BF::TYPE_SPELL_SELECT:
×
344
    do_cast( client, cfBEu16( msg->spellselect.selected_spell ) );
×
345
    break;
×
346
  case PKTBI_BF::TYPE_CHARACTER_RACE_CHANGER:
×
347
    Module::character_race_changer_handler( client, msg );
×
348
    break;
×
349
  case PKTBI_BF::TYPE_PARTY_SYSTEM:
×
350
    party_cmd_handler( client, msg );
×
351
    break;
×
352
  case PKTBI_BF::TYPE_EXTENDED_STATS_IN:
×
353
    ext_stats_in( client, msg );
×
354
    break;
×
355
  case PKTBI_BF::TYPE_CLOSED_STATUS_GUMP:
×
356
    return;
×
357
    break;
358
  case PKTBI_BF::TYPE_SCREEN_SIZE:
×
359
    return;
×
360
    break;
361
  case PKTBI_BF::TYPE_TOGGLE_FLYING:
×
362
    if ( client->chr->race == Plib::RACE_GARGOYLE )
×
363
    {
364
      // FIXME: add checks if its possible to stand with new movemode
NEW
365
      client->chr->movemode = (Plib::MOVEMODE)( client->chr->movemode ^ Plib::MOVEMODE_FLY );
×
366
      send_move_mobile_to_nearby_cansee( client->chr );
×
367
      send_goxyz( client, client->chr );
×
368
    }
369
    break;
×
370
  case PKTBI_BF::TYPE_CLIENTTYPE:
2✔
371
    client->UOExpansionFlagClient = ctBEu32( msg->clienttype.clientflag );
2✔
372
    break;
2✔
373
  case PKTBI_BF::TYPE_POPUP_MENU_REQUEST:
×
374
  {
375
    ref_ptr<Bscript::EScriptProgram> prog =
376
        find_script( "misc/popupmenu", true, Plib::systemstate.config.cache_interactive_scripts );
×
377
    if ( prog.get() == nullptr )
×
378
      break;
×
379
    u32 serial = cfBEu32( msg->serial_request_popup_menu );
×
380
    if ( IsCharacter( serial ) )
×
381
    {
382
      Pol::Mobile::Character* chr = system_find_mobile( serial );
×
383
      if ( chr == nullptr )
×
384
        break;
×
385
      client->chr->start_script( prog.get(), false, new Pol::Module::ECharacterRefObjImp( chr ) );
×
386
    }
387
    else
388
    {
389
      Pol::Items::Item* item = system_find_item( serial );
×
390
      if ( item == nullptr )
×
391
        break;
×
392
      client->chr->start_script( prog.get(), false, item->make_ref() );
×
393
    }
394
    break;
×
395
  }
×
396
  case PKTBI_BF::TYPE_POPUP_ENTRY_SELECT:
×
397
  {
398
    if ( client->gd->on_popup_menu_selection == nullptr )
×
399
    {
400
      POLLOG_INFOLN( "{}/{} tried to use a popup menu, but none was active.", client->acct->name(),
×
401
                     client->chr->name() );
×
402
      break;
×
403
    }
404

405
    u32 serial = cfBEu32( msg->popupselect.serial );
×
406
    u16 id = cfBEu16( msg->popupselect.entry_tag );
×
407
    client->gd->on_popup_menu_selection( client, serial, id );
×
408
    break;
×
409
  }
410
  case PKTBI_BF::TYPE_BOAT_MOVE:
3✔
411
  {
412
    Mobile::Character* chr = client->chr;
3✔
413
    multi = chr->realm()->find_supporting_multi( client->chr->pos3d() );
3✔
414

415
    if ( multi == nullptr )
3✔
416
    {
417
      SuspiciousActs::BoatMoveNoMulti( client );
×
418
      break;
×
419
    }
420

421
    if ( !multi->script_isa( Core::POLCLASS_BOAT ) )
3✔
422
    {
423
      SuspiciousActs::BoatMoveNotBoatMulti( client );
×
424
      break;
×
425
    }
426

427
    Multi::UBoat* boat = static_cast<Multi::UBoat*>( multi );
3✔
428
    if ( boat->pilot() != chr )
3✔
429
    {
430
      SuspiciousActs::BoatMoveNotPilot( client, multi->serial );
×
431
      break;
×
432
    }
433

434
    if ( msg->boatmove.direction > 7 || msg->boatmove.speed > 2 )
3✔
435
    {
436
      SuspiciousActs::BoatMoveOutOfRangeParameters( client, multi->serial, msg->boatmove.direction,
×
437
                                                    msg->boatmove.speed );
×
438
      break;
×
439
    }
440

441
    Module::UOExecutorModule* process = multi->process();
3✔
442
    if ( !process )
3✔
443
    {
444
      break;
×
445
    }
446

447
    auto relative_direction =
448
        static_cast<Core::UFACING>( ( msg->boatmove.direction - boat->boat_facing() + 8 ) & 7 );
3✔
449

450
    process->uoexec().signal_event( new Module::BoatMovementEvent(
6✔
451
        chr, msg->boatmove.speed, msg->boatmove.direction, relative_direction ) );
3✔
452

453
    break;
3✔
454
  }
455
  default:
×
456
    handle_unknown_packet( client );
×
457
  }
458
}
459

460
void handle_unknown_C4( Client* client, PKTOUT_C4* /*msg*/ )
×
461
{
462
  handle_unknown_packet( client );
×
463
}
×
464

465
void handle_update_range_change( Client* client, PKTBI_C8* msg )
2✔
466
{
467
  client->set_update_range_by_client( msg->range );
2✔
468
}
2✔
469

470
void handle_krrios_packet( Client* client, PKTBI_F0* msg )
×
471
{
472
  auto* me = client->chr;
×
473
  switch ( msg->subcmd )
×
474
  {
475
  case PKTBI_F0::QUERY_PARTY:
×
476
  {
477
    if ( !settingsManager.ssopt.enable_worldmap_packets )
×
478
      break;
×
479

480
    if ( me->has_party() )
×
481
    {
482
      Party* party = me->party();
×
483
      Network::PktHelper::PacketOut<Network::PktOut_F0_Sub01> outMsg;
×
484
      outMsg->offset += 2;                              // len
×
485
      outMsg->Write<u8>( PKTBI_F0::QUERY_PARTY + 1U );  // sub, response is +1
×
486
      for ( auto member : party->get_members() )
×
487
      {
488
        if ( member->serial == me->serial )
×
489
          continue;
×
490

491
        if ( me->is_visible_to_me( member ) )
×
492
          continue;
×
493

494
        outMsg->Write<u32>( member->serial_ext );
×
495
        outMsg->WriteFlipped<u16>( member->x() );
×
496
        outMsg->WriteFlipped<u16>( member->y() );
×
497
        outMsg->Write<u8>( member->realm()->getUOMapID() );
×
498
      }
×
499

500
      if ( outMsg->offset != 4 )  // only send if there is an update
×
501
      {
502
        outMsg->Write<u32>( 0U );  // end of list marker
×
503
        u16 len = outMsg->offset;
×
504
        outMsg->offset = 1;
×
505
        outMsg->WriteFlipped<u16>( len );
×
506
        outMsg.Send( client, len );
×
507
      }
508
    }
×
509
    break;
×
510
  }
511
  case PKTBI_F0::QUERY_GUILD:
×
512
  {
513
    if ( !settingsManager.ssopt.enable_worldmap_packets )
×
514
      break;
×
515

516
    Guild* guild = me->guild();
×
517
    u8 locations = msg->query_guild.include_locations > 0 ? 1U : 0U;
×
518
    if ( guild != nullptr )
×
519
    {
520
      Network::PktHelper::PacketOut<Network::PktOut_F0_Sub02> outMsg;
×
521
      outMsg->offset += 2;                              // len
×
522
      outMsg->Write<u8>( PKTBI_F0::QUERY_GUILD + 1U );  // sub, response is +1
×
523
      outMsg->Write<u8>( locations );
×
524
      for ( auto member : guild->get_members() )
×
525
      {
526
        if ( member->serial == me->serial )
×
527
          continue;
×
528

529
        if ( locations && me->is_visible_to_me( member ) )
×
530
          continue;
×
531

532
        outMsg->Write<u32>( member->serial_ext );
×
533
        if ( locations )
×
534
        {
535
          outMsg->WriteFlipped<u16>( member->x() );
×
536
          outMsg->WriteFlipped<u16>( member->y() );
×
537
          outMsg->Write<u8>( member->realm()->getUOMapID() );
×
538

539
          if ( member->dead() )
×
540
            outMsg->Write<u8>( 0U );
×
541
          else
542
          {
543
            int current = member->vital( networkManager.uoclient_general.hits.id ).current_ones();
×
544
            int max = member->vital( networkManager.uoclient_general.hits.id ).maximum_ones();
×
545
            u8 ratio = static_cast<u8>( 100 * current / ( max < 1 ? 1 : max ) );
×
546
            outMsg->Write<u8>( ratio );  // hits
×
547
          }
548
        }
549
      }
×
550
      if ( outMsg->offset != 5 )  // only send if there is an update
×
551
      {
552
        outMsg->Write<u32>( 0U );  // end of list marker
×
553
        u16 len = outMsg->offset;
×
554
        outMsg->offset = 1;
×
555
        outMsg->WriteFlipped<u16>( len );
×
556
        outMsg.Send( client, len );
×
557
      }
558
    }
×
559
    break;
×
560
  }
561
  default:
×
562
    handle_unknown_packet( client );
×
563
    break;
×
564
  }
565
}
×
566

567
void handle_open_uo_store( Client* client, PKTIN_FA* /*msg*/ )
×
568
{
569
  handle_unknown_packet( client );
×
570
}
×
571

572
void handle_update_view_public_house_content( Client* client, PKTIN_FB* /*msg*/ )
×
573
{
574
  handle_unknown_packet( client );
×
575
}
×
576

577
void handle_allnames( Client* client, PKTBI_98_IN* msg )
×
578
{
579
  u32 serial = cfBEu32( msg->serial );
×
580
  Mobile::Character* the_mob = find_character( serial );
×
581
  if ( the_mob == nullptr )
×
582
    return;
×
583
  if ( !client->chr->is_visible_to_me( the_mob ) )
×
584
    return;
×
585

586
  PktHelper::PacketOut<PktOut_98> msgOut;
×
587
  msgOut->WriteFlipped<u16>( 37u );  // static length
×
588
  msgOut->Write<u32>( the_mob->serial_ext );
×
589
  msgOut->Write( Clib::strUtf8ToCp1252( the_mob->name() ).c_str(), 30, false );
×
590
  msgOut.Send( client );
×
591
}
×
592

593
void handle_se_object_list( Client* client, PKTBI_D6_IN* msgin )
4✔
594
{
595
  UObject* obj = nullptr;
4✔
596
  int length = cfBEu16( msgin->msglen ) - 3;
4✔
597
  if ( length < 0 || ( length % 4 ) != 0 )
4✔
598
    return;
×
599
  int count = length / 4;
4✔
600

601
  for ( int i = 0; i < count; ++i )
8✔
602
  {
603
    obj = system_find_object( cfBEu32( msgin->serials[i].serial ) );
4✔
604
    if ( obj != nullptr )
4✔
605
      SendAOSTooltip( client, obj );
4✔
606
  }
607
}
608

609
void handle_ef_seed( Client* client, PKTIN_EF* msg )
2✔
610
{
611
  VersionDetailStruct detail;
612
  detail.major = cfBEu32( msg->ver_Major );
2✔
613
  detail.minor = cfBEu32( msg->ver_Minor );
2✔
614
  detail.rev = cfBEu32( msg->ver_Revision );
2✔
615
  detail.patch = cfBEu32( msg->ver_Patch );
2✔
616
  client->setversiondetail( detail );
2✔
617
  if ( client->compareVersion( CLIENT_VER_70331 ) )
2✔
618
    client->setClientType( CLIENTTYPE_70331 );
×
619
  else if ( client->compareVersion( CLIENT_VER_70300 ) )
2✔
620
    client->setClientType( CLIENTTYPE_70300 );
×
621
  else if ( client->compareVersion( CLIENT_VER_70130 ) )
2✔
622
    client->setClientType( CLIENTTYPE_70130 );
×
623
  else if ( client->compareVersion( CLIENT_VER_7090 ) )
2✔
624
    client->setClientType( CLIENTTYPE_7090 );
2✔
625
  else if ( client->compareVersion( CLIENT_VER_7000 ) )
×
626
    client->setClientType( CLIENTTYPE_7000 );
×
627
  else if ( client->compareVersion( CLIENT_VER_60142 ) )
×
628
    client->setClientType( CLIENTTYPE_60142 );
×
629
  else if ( client->compareVersion( CLIENT_VER_6017 ) )  // Grid-loc support
×
630
    client->setClientType( CLIENTTYPE_6017 );
×
631
  else if ( client->compareVersion( CLIENT_VER_5020 ) )
×
632
    client->setClientType( CLIENTTYPE_5020 );
×
633
  else if ( client->compareVersion( CLIENT_VER_5000 ) )
×
634
    client->setClientType( CLIENTTYPE_5000 );
×
635
  else if ( client->compareVersion( CLIENT_VER_4070 ) )
×
636
    client->setClientType( CLIENTTYPE_4070 );
×
637
  else if ( client->compareVersion( CLIENT_VER_4000 ) )
×
638
    client->setClientType( CLIENTTYPE_4000 );
×
639

640
  // detail->patch is since 5.0.7 always numeric, so no need to make it complicated
641
  client->setversion(
4✔
642
      fmt::format( "{}.{}.{}.{}", detail.major, detail.minor, detail.rev, detail.patch ) );
4✔
643
}
2✔
644

645
void handle_e1_clienttype( Client* client, PKTIN_E1* msg )
×
646
{
647
  switch ( cfBEu32( msg->clienttype ) )
×
648
  {
649
  case PKTIN_E1::CLIENTTYPE_KR:
×
650
    client->setClientType( CLIENTTYPE_UOKR );
×
651
    break;
×
652
  case PKTIN_E1::CLIENTTYPE_SA:
×
653
    client->setClientType( CLIENTTYPE_UOSA );
×
654
    break;
×
655
  default:
×
656
    INFO_PRINTLN( "Unknown client type send with packet 0xE1 : {:#x}",
×
657
                  static_cast<unsigned long>( cfBEu32( msg->clienttype ) ) );
×
658
    break;
×
659
  }
660
}
×
661

662

663
/**
664
 * Handler for a 0xD7 packet
665
 */
666
void handle_aos_commands( Client* client, PKTBI_D7* msg )
×
667
{
668
  // nullptr prevention, no need to disturb if client or character is not found
669
  if ( client == nullptr || client->chr == nullptr )
×
670
    return;
×
671

672
  /// Checks that serial written inside packet matches sending character's serial
673
  u32 serial = cfBEu32( msg->serial );
×
674
  if ( client && client->chr && client->chr->serial != serial )
×
675
  {
676
    INFO_PRINTLN( "Ignoring spoofed packet 0xD7 from character {:#x} trying to spoof {:#x}",
×
677
                  client->chr->serial, serial );
×
678
    return;
×
679
  }
680

681
  switch ( cfBEu16( msg->subcmd ) )
×
682
  {
683
  case PKTBI_D7::CUSTOM_HOUSE_BACKUP:
×
684
    Multi::CustomHousesBackup( msg );
×
685
    break;
×
686

687
  case PKTBI_D7::CUSTOM_HOUSE_RESTORE:
×
688
    Multi::CustomHousesRestore( msg );
×
689
    break;
×
690

691
  case PKTBI_D7::CUSTOM_HOUSE_COMMIT:
×
692
    Multi::CustomHousesCommit( msg );
×
693
    break;
×
694

695
  case PKTBI_D7::CUSTOM_HOUSE_ERASE:
×
696
    Multi::CustomHousesErase( msg );
×
697
    break;
×
698

699
  case PKTBI_D7::CUSTOM_HOUSE_ADD:
×
700
    Multi::CustomHousesAdd( msg );
×
701
    break;
×
702

703
  case PKTBI_D7::CUSTOM_HOUSE_QUIT:
×
704
    Multi::CustomHousesQuit( msg );
×
705
    break;
×
706

707
  case PKTBI_D7::CUSTOM_HOUSE_ADD_MULTI:
×
708
    Multi::CustomHousesAddMulti( msg );
×
709
    break;
×
710

711
  case PKTBI_D7::CUSTOM_HOUSE_SYNCH:
×
712
    Multi::CustomHousesSynch( msg );
×
713
    break;
×
714

715
  case PKTBI_D7::CUSTOM_HOUSE_CLEAR:
×
716
    Multi::CustomHousesClear( msg );
×
717
    break;
×
718

719
  case PKTBI_D7::CUSTOM_HOUSE_SELECT_FLOOR:
×
720
    Multi::CustomHousesSelectFloor( msg );
×
721
    break;
×
722

723
  case PKTBI_D7::CUSTOM_HOUSE_REVERT:
×
724
    Multi::CustomHousesRevert( msg );
×
725
    break;
×
726
  case PKTBI_D7::CUSTOM_HOUSE_SELECT_ROOF:
×
727
    Multi::CustomHousesRoofSelect( msg );
×
728
    break;
×
729
  case PKTBI_D7::CUSTOM_HOUSE_DELETE_ROOF:
×
730
    Multi::CustomHousesRoofRemove( msg );
×
731
    break;
×
732
  case PKTBI_D7::GUILD_BUTTON:
×
733
    OnGuildButton( client );
×
734
    break;
×
735
  case PKTBI_D7::QUEST_BUTTON:
×
736
    OnQuestButton( client );
×
737
    break;
×
738
  // missing combat book abilities
739
  default:
×
740
    handle_unknown_packet( client );
×
741
  }
742
}
743

744
void OnGuildButton( Client* client )
×
745
{
746
  ref_ptr<Bscript::EScriptProgram> prog =
747
      find_script( "misc/guildbutton", true, Plib::systemstate.config.cache_interactive_scripts );
×
748
  if ( prog.get() != nullptr )
×
749
  {
750
    client->chr->start_script( prog.get(), false );
×
751
  }
752
}
×
753

754
void OnQuestButton( Client* client )
×
755
{
756
  ref_ptr<Bscript::EScriptProgram> prog =
757
      find_script( "misc/questbutton", true, Plib::systemstate.config.cache_interactive_scripts );
×
758
  if ( prog.get() != nullptr )
×
759
  {
760
    client->chr->start_script( prog.get(), false );
×
761
  }
762
}
×
763

764
void OnChatButton( Client* client )
×
765
{
766
  ref_ptr<Bscript::EScriptProgram> prog =
767
      find_script( "misc/chatbutton", true, Plib::systemstate.config.cache_interactive_scripts );
×
768
  if ( prog.get() != nullptr )
×
769
  {
770
    client->chr->start_script( prog.get(), false );
×
771
  }
772
}
×
773
}  // namespace Core
774
}  // namespace Pol
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc