13
13
14
14
std::map<CNSocket*, CNLoginData> CNLoginServer::loginSessions;
15
15
16
+ namespace LoginServer {
17
+ std::vector<std::string> WheelFirstNames;
18
+ std::vector<std::string> WheelMiddleNames;
19
+ std::vector<std::string> WheelLastNames;
20
+ }
21
+
16
22
CNLoginServer::CNLoginServer (uint16_t p) {
17
23
serverType = " login" ;
18
24
port = p;
@@ -286,10 +292,29 @@ void CNLoginServer::nameSave(CNSocket* sock, CNPacketData* data) {
286
292
INITSTRUCT (sP_LS2CL_REP_SAVE_CHAR_NAME_SUCC , resp);
287
293
288
294
int errorCode = 0 ;
289
- if (!CNLoginServer::isCharacterNameGood (AUTOU16TOU8 (save->szFirstName ), AUTOU16TOU8 (save->szLastName ))) {
290
- errorCode = 4 ;
291
- } else if (!Database::isNameFree (AUTOU16TOU8 (save->szFirstName ), AUTOU16TOU8 (save->szLastName ))) {
292
- errorCode = 1 ;
295
+
296
+ std::string firstName = AUTOU16TOU8 (save->szFirstName );
297
+ std::string lastName = AUTOU16TOU8 (save->szLastName );
298
+ int nameCheck = 0 ;
299
+
300
+ // if FNCode isn't 0, it's a wheel name
301
+ if (save->iFNCode != 0 ) {
302
+ if (!CNLoginServer::isNameWheelNameGood (save->iFNCode , save->iMNCode , save->iLNCode , firstName, lastName)) {
303
+ errorCode = 4 ;
304
+ } else {
305
+ nameCheck = settings:: APPROVEWHEELNAMES ? 1 : 0 ;
306
+ }
307
+ } else {
308
+ // custom name
309
+ nameCheck = settings::APPROVECUSTOMNAMES ? 1 : 0 ;
310
+ }
311
+
312
+ if (errorCode == 0 ) {
313
+ if (!CNLoginServer::isCharacterNameGood (firstName, lastName)) {
314
+ errorCode = 4 ;
315
+ } else if (!Database::isNameFree (firstName, lastName)) {
316
+ errorCode = 1 ;
317
+ }
293
318
}
294
319
295
320
if (errorCode != 0 ) {
@@ -307,19 +332,16 @@ void CNLoginServer::nameSave(CNSocket* sock, CNPacketData* data) {
307
332
if (!Database::isSlotFree (loginSessions[sock].userID , save->iSlotNum ))
308
333
return invalidCharacter (sock);
309
334
310
- resp.iPC_UID = Database::createCharacter (save, loginSessions[sock].userID );
335
+ resp.iPC_UID = Database::createCharacter (save-> iSlotNum , loginSessions[sock].userID , firstName. c_str (), lastName. c_str (), nameCheck );
311
336
// if query somehow failed
312
337
if (resp.iPC_UID == 0 ) {
313
338
std::cout << " [WARN] Login Server: Database failed to create new character!" << std::endl;
314
339
return invalidCharacter (sock);
315
340
}
316
341
317
- Player plr;
318
- Database::getPlayer (&plr, (int )resp.iPC_UID );
319
-
320
342
// fire name check event if needed
321
- if (plr. PCStyle . iNameCheck != 1 ) {
322
- std::string namereq = std::to_string (resp.iPC_UID ) + " " + AUTOU16TOU8 (save-> szFirstName ) + " " + AUTOU16TOU8 (save-> szLastName ) ;
343
+ if (nameCheck != 1 ) {
344
+ std::string namereq = std::to_string (resp.iPC_UID ) + " " + firstName + " " + lastName ;
323
345
Monitor::namereqs.push_back (namereq);
324
346
}
325
347
@@ -338,8 +360,8 @@ void CNLoginServer::nameSave(CNSocket* sock, CNPacketData* data) {
338
360
DEBUGLOG (
339
361
std::cout << " Login Server: new character created" << std::endl;
340
362
std::cout << " \t Slot: " << (int )save->iSlotNum << std::endl;
341
- std::cout << " \t Name: " << AUTOU16TOU8 (save-> szFirstName ) << " " << AUTOU16TOU8 (save-> szLastName ) ;
342
- if (plr. PCStyle . iNameCheck != 1 ) std::cout << " (pending approval)" ;
363
+ std::cout << " \t Name: " << firstName << " " << lastName ;
364
+ if (nameCheck != 1 ) std::cout << " (pending approval)" ;
343
365
std::cout << std::endl;
344
366
)
345
367
}
@@ -507,11 +529,30 @@ void CNLoginServer::changeName(CNSocket* sock, CNPacketData* data) {
507
529
auto save = (sP_CL2LS_REQ_CHANGE_CHAR_NAME *)data->buf ;
508
530
509
531
int errorCode = 0 ;
510
- if (!CNLoginServer::isCharacterNameGood (AUTOU16TOU8 (save->szFirstName ), AUTOU16TOU8 (save->szLastName ))) {
511
- errorCode = 4 ;
532
+
533
+ std::string firstName = AUTOU16TOU8 (save->szFirstName );
534
+ std::string lastName = AUTOU16TOU8 (save->szLastName );
535
+ int nameCheck = 0 ;
536
+
537
+ // if FNCode isn't 0, it's a wheel name
538
+ if (save->iFNCode != 0 ) {
539
+ if (!CNLoginServer::isNameWheelNameGood (save->iFNCode , save->iMNCode , save->iLNCode , firstName, lastName)) {
540
+ errorCode = 4 ;
541
+ } else {
542
+ nameCheck = settings::APPROVEWHEELNAMES ? 1 : 0 ;
543
+ }
544
+ } else {
545
+ // custom name
546
+ nameCheck = settings::APPROVECUSTOMNAMES ? 1 : 0 ;
512
547
}
513
- else if (!Database::isNameFree (AUTOU16TOU8 (save->szFirstName ), AUTOU16TOU8 (save->szLastName ))) {
514
- errorCode = 1 ;
548
+
549
+ if (errorCode == 0 ) {
550
+ if (!CNLoginServer::isCharacterNameGood (firstName, lastName)) {
551
+ errorCode = 4 ;
552
+ }
553
+ else if (!Database::isNameFree (firstName, lastName)) {
554
+ errorCode = 1 ;
555
+ }
515
556
}
516
557
517
558
if (errorCode != 0 ) {
@@ -526,15 +567,12 @@ void CNLoginServer::changeName(CNSocket* sock, CNPacketData* data) {
526
567
return ;
527
568
}
528
569
529
- if (!Database::changeName (save, loginSessions[sock].userID ))
570
+ if (!Database::changeName (save-> iPCUID , loginSessions[sock].userID , firstName. c_str (), lastName. c_str (), nameCheck ))
530
571
return invalidCharacter (sock);
531
572
532
- Player plr;
533
- Database::getPlayer (&plr, (int )save->iPCUID );
534
-
535
573
// fire name check event if needed
536
- if (plr. PCStyle . iNameCheck != 1 ) {
537
- std::string namereq = std::to_string (save->iPCUID ) + " " + AUTOU16TOU8 (save-> szFirstName ) + " " + AUTOU16TOU8 (save-> szLastName ) ;
574
+ if (nameCheck != 1 ) {
575
+ std::string namereq = std::to_string (save->iPCUID ) + " " + firstName + " " + lastName ;
538
576
Monitor::namereqs.push_back (namereq);
539
577
}
540
578
@@ -550,8 +588,8 @@ void CNLoginServer::changeName(CNSocket* sock, CNPacketData* data) {
550
588
551
589
DEBUGLOG (
552
590
std::cout << " Login Server: Name change request for character [" << save->iPCUID << " ]" << std::endl;
553
- std::cout << " \t New name: " << AUTOU16TOU8 (save-> szFirstName ) << " " << AUTOU16TOU8 (save-> szLastName ) ;
554
- if (plr. PCStyle . iNameCheck != 1 ) std::cout << " (pending approval)" ;
591
+ std::cout << " \t New name: " << firstName << " " << lastName ;
592
+ if (nameCheck != 1 ) std::cout << " (pending approval)" ;
555
593
std::cout << std::endl;
556
594
)
557
595
}
@@ -645,6 +683,42 @@ bool CNLoginServer::isPasswordCorrect(std::string actualPassword, std::string tr
645
683
return BCrypt::validatePassword (tryPassword, actualPassword);
646
684
}
647
685
686
+ bool CNLoginServer::isNameWheelNameGood (int fnCode, int mnCode, int lnCode, std::string& firstName, std::string& lastName) {
687
+ if (fnCode >= LoginServer::WheelFirstNames.size ()
688
+ || mnCode >= LoginServer::WheelMiddleNames.size ()
689
+ || lnCode >= LoginServer::WheelLastNames.size ()) {
690
+ std::cout << " [WARN] Login Server: Invalid name codes received: " << fnCode << " " << mnCode << " " << lnCode << std::endl;
691
+ return false ;
692
+ }
693
+
694
+ // client sends 1 if not selected for these. they point to a single blank space. why.
695
+ // just change them to 0, which points to an empty string; keeps the code much cleaner
696
+ if (mnCode == 1 ) mnCode = 0 ;
697
+ if (lnCode == 1 ) lnCode = 0 ;
698
+
699
+ std::string firstNameFromWheel = LoginServer::WheelFirstNames[fnCode];
700
+
701
+ std::string middleNamePart = LoginServer::WheelMiddleNames[mnCode];
702
+ std::string lastNamePart = LoginServer::WheelLastNames[lnCode];
703
+ if (mnCode != 0 && middleNamePart[middleNamePart.size () - 1 ] != ' ' ) {
704
+ // If there's a middle name, we need to lowercase the last name
705
+ std::transform (lastNamePart.begin (), lastNamePart.end (), lastNamePart.begin (), ::tolower);
706
+ }
707
+ std::string lastNameFromWheel = middleNamePart + lastNamePart;
708
+
709
+ if (firstNameFromWheel.empty () || lastNameFromWheel.empty ()) {
710
+ std::cout << " [WARN] Login Server: Invalid wheel name combo: " << fnCode << " " << mnCode << " " << lnCode << std::endl;
711
+ return false ;
712
+ }
713
+
714
+ if (firstName != firstNameFromWheel || lastName != lastNameFromWheel) {
715
+ std::cout << " [WARN] Login Server: Name wheel mismatch. Expected " << firstNameFromWheel << " " << lastNameFromWheel << " , got " << firstName << " " << lastName << std::endl;
716
+ return false ;
717
+ }
718
+
719
+ return true ;
720
+ }
721
+
648
722
bool CNLoginServer::isCharacterNameGood (std::string Firstname, std::string Lastname) {
649
723
// Allow alphanumeric and dot characters in names(disallows dot and space characters at the beginning of a name)
650
724
std::regex firstnamecheck (R"( ((?! )(?!\.)[a-zA-Z0-9]*\.{0,1}(?!\.+ +)[a-zA-Z0-9]* {0,1}(?! +))*$)" );
0 commit comments