mirror of
https://github.com/UOX3DevTeam/UOX3
synced 2026-08-13 12:27:04 -04:00
Added new system that lets shard admins assign a "network" budget to connected clients, which determines the maximum amount of bytes clients are allowed to send to/receive from server over a period of ten seconds. If a client exceeds these limits three times in the same connected session, they'll receive a temporary ban and get kicked from the server. The following new UOX.INI settings under the [system] section can be used to control this feature: MAXCLIENTBYTESIN=25000 // Max bytes client can send to server over 10 seconds MAXCLIENTBYTESOUT=100000 // Max bytes client can receive from server over 10 seconds NETTRAFFICTIMEBAN=30 // Duration (in minutes) of temporary ban for exceeding these limits Fixed an issue that prevented GMs from using CSTATS and TWEAK buttons in 'wholist Updated documentation with most recent changes to UOX.INI settings Minor code cleanup
510 lines
18 KiB
C++
510 lines
18 KiB
C++
#include "uox3.h"
|
|
#include "wholist.h"
|
|
#include "network.h"
|
|
#include "CPacketSend.h"
|
|
#include "Dictionary.h"
|
|
#include "jail.h"
|
|
#include "commands.h"
|
|
|
|
|
|
cWhoList *WhoList;
|
|
cWhoList *OffList;
|
|
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Function - void ResetUpdateFlag( void )
|
|
//| Date - 12th February, 2000
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Purpose - Disables the WhoList update flag
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
void cWhoList::ResetUpdateFlag( void )
|
|
{
|
|
needsUpdating = false;
|
|
}
|
|
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Class - cWhoList( bool trulyOnline )
|
|
//| Date - 12th February, 2000
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Purpose - Initializes the variables of the wholist on creation
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
cWhoList::cWhoList( bool trulyOnline )
|
|
{
|
|
FlagUpdate(); // first use will force it to update
|
|
gmCount = 0; // no GMs currently using it
|
|
whoMenuData.resize( 0 );
|
|
online = trulyOnline;
|
|
}
|
|
|
|
cWhoList::~cWhoList()
|
|
// PRE: WhoList class is active
|
|
// POST: Memory cleared/destroyed
|
|
// DATE: 12th February, 2000
|
|
{
|
|
ResetUpdateFlag();
|
|
gmCount = 0;
|
|
Delete();
|
|
}
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Function - void ResetUpdateFlag( void )
|
|
//| Date - 12th February, 2000
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Purpose - Flags the WhoList as needing to be updated
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
void cWhoList::FlagUpdate( void )
|
|
{
|
|
needsUpdating = true;
|
|
}
|
|
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Function - void SendSocket( CSocket *toSendTo )
|
|
//| Date - 12th February, 2000
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Purpose - Sends the WhoList to a player's socket
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
void cWhoList::SendSocket( CSocket *toSendTo )
|
|
{
|
|
GMEnter();
|
|
if( needsUpdating && gmCount <= 1 ) // If we need to update, do it now while we still can
|
|
Update();
|
|
|
|
if( online )
|
|
SendVecsAsGump( toSendTo, one, two, 4, INVALIDSERIAL );
|
|
else
|
|
SendVecsAsGump( toSendTo, one, two, 11, INVALIDSERIAL );
|
|
}
|
|
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Function - void GMEnter( void )
|
|
//| Date - 12th February, 2000
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Purpose - Increments the GM counter
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
void cWhoList::GMEnter( void )
|
|
{
|
|
++gmCount;
|
|
}
|
|
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Function - void GMLeave( void )
|
|
//| Date - 12th February, 2000
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Purpose - Decrements the GM counter
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
void cWhoList::GMLeave( void )
|
|
{
|
|
if( gmCount != 0 )
|
|
--gmCount;
|
|
}
|
|
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Function - void Delete( void )
|
|
//| Date - 12th February, 2000
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Purpose - Deletes all the entries in the WhoList
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
void cWhoList::Delete( void )
|
|
{
|
|
one.resize( 0 );
|
|
two.resize( 0 );
|
|
whoMenuData.resize( 0 );
|
|
|
|
}
|
|
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Function - void AddSerial( SERIAL toAdd )
|
|
//| Date - 23rd February, 2000
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Purpose - Adds an entry into the whoMenuData array
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
void cWhoList::AddSerial( SERIAL toAdd )
|
|
{
|
|
whoMenuData.push_back( toAdd );
|
|
}
|
|
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Function - void ButtonSelect( CSocket *toSendTo, UI16 buttonPressed, UI08 type )
|
|
//| Date - 23rd February, 2000
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Purpose - Does action based upon button selected
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
void cWhoList::ButtonSelect( CSocket *toSendTo, UI16 buttonPressed, UI08 type )
|
|
{
|
|
CChar *sourceChar = toSendTo->CurrcharObj();
|
|
|
|
if( buttonPressed < 200 )
|
|
{
|
|
if( buttonPressed == 0 )
|
|
return;
|
|
buttonPressed -= 7;
|
|
toSendTo->AddID( buttonPressed );
|
|
Command( toSendTo, type, buttonPressed );
|
|
return;
|
|
}
|
|
|
|
GMLeave();
|
|
SERIAL ser = toSendTo->AddID();
|
|
if( ser == INVALIDSERIAL )
|
|
{
|
|
toSendTo->sysmessage( 1387 ); // Selected character not found.
|
|
return;
|
|
}
|
|
|
|
SERIAL charSerial = whoMenuData[ser];
|
|
|
|
CChar *targetChar = calcCharObjFromSer( charSerial ); // find selected char ...
|
|
if( !ValidateObject( targetChar ) )
|
|
{
|
|
toSendTo->sysmessage( 1387 ); // Selected character not found.
|
|
return;
|
|
}
|
|
CSocket *trgSock = nullptr;
|
|
switch( buttonPressed )
|
|
{
|
|
case 200://gochar
|
|
if( targetChar->GetCommandLevel() > sourceChar->GetCommandLevel() )
|
|
{
|
|
toSendTo->sysmessage( 1388 ); // You cannot go to such powerful beings.
|
|
return;
|
|
}
|
|
if( sourceChar->WorldNumber() != targetChar->WorldNumber() )
|
|
{
|
|
sourceChar->SetLocation( targetChar );
|
|
SendMapChange( targetChar->WorldNumber(), toSendTo );
|
|
}
|
|
else
|
|
sourceChar->SetLocation( targetChar );
|
|
break;
|
|
case 201://xtele
|
|
if( targetChar->GetCommandLevel() > sourceChar->GetCommandLevel() )
|
|
{
|
|
toSendTo->sysmessage( 1389 ); // Such powerful beings don't come on your whim!
|
|
return;
|
|
}
|
|
if( !targetChar->IsNpc() && targetChar->WorldNumber() != sourceChar->WorldNumber() )
|
|
{
|
|
targetChar->SetLocation( sourceChar );
|
|
trgSock = targetChar->GetSocket();
|
|
SendMapChange( sourceChar->WorldNumber(), trgSock );
|
|
}
|
|
else
|
|
targetChar->SetLocation( sourceChar );
|
|
break;
|
|
case 202://jail char
|
|
if( sourceChar == targetChar )
|
|
{
|
|
toSendTo->sysmessage( 1390 ); // You cannot jail yourself!
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if( targetChar->GetCommandLevel() > sourceChar->GetCommandLevel() )
|
|
{
|
|
toSendTo->sysmessage( 1391 ); // You cannot jail someone superior to you.
|
|
return;
|
|
}
|
|
if( targetChar->IsJailed() )
|
|
toSendTo->sysmessage( 1070 ); // That player is already in jail!
|
|
|
|
else if( !JailSys->JailPlayer( targetChar, 0xFFFFFFFF ) )
|
|
toSendTo->sysmessage( 1072 ); // All jails are currently full!
|
|
break;
|
|
}
|
|
case 203://release
|
|
if( targetChar->GetCommandLevel() > sourceChar->GetCommandLevel() )
|
|
{
|
|
toSendTo->sysmessage( 1392 ); // You release someone more powerful than you.
|
|
return;
|
|
}
|
|
if( !targetChar->IsJailed() )
|
|
toSendTo->sysmessage( 1064 ); // That player is not in jail!
|
|
else
|
|
{
|
|
JailSys->ReleasePlayer( targetChar );
|
|
toSendTo->sysmessage( 1065, targetChar->GetName().c_str() ); // Player %s released.
|
|
}
|
|
break;
|
|
case 204:
|
|
if( targetChar == sourceChar )
|
|
{
|
|
toSendTo->sysmessage( 1393 ); // You cannot kick yourself.
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if( !isOnline( (*targetChar) ) ) // local var overloads it
|
|
{
|
|
toSendTo->sysmessage( 1394 ); // You can't kick an offline player.
|
|
break;
|
|
}
|
|
if( targetChar->GetCommandLevel() > sourceChar->GetCommandLevel() )
|
|
{
|
|
toSendTo->sysmessage( 1395 ); // You cannot kick someone more powerful than you.
|
|
return;
|
|
}
|
|
toSendTo->sysmessage( 1396 ); // Kicking player.
|
|
Network->Disconnect( targetChar->GetSocket() );
|
|
break;
|
|
}
|
|
case 205:
|
|
// make it prettier later!
|
|
if( targetChar->GetCommandLevel() > sourceChar->GetCommandLevel() )
|
|
{
|
|
toSendTo->sysmessage( 1397 ); // You cannot spy on your betters.
|
|
return;
|
|
}
|
|
toSendTo->sysmessage( "X: %i Y: %i Z: %i World: %u", targetChar->GetX(), targetChar->GetY(), targetChar->GetZ(), targetChar->WorldNumber() );
|
|
break;
|
|
case 206: // remote cstats
|
|
if( targetChar->GetCommandLevel() > sourceChar->GetCommandLevel() )
|
|
{
|
|
toSendTo->sysmessage( 1398 ); // You have not the right to see the intimate details of your betters!
|
|
return;
|
|
}
|
|
toSendTo->SetDWord( 7, targetChar->GetSerial() );
|
|
// Trigger scripted command
|
|
Commands->Command( toSendTo, targetChar, "cstats", true );
|
|
break;
|
|
case 207: // remote tweak
|
|
if( targetChar->GetCommandLevel() > sourceChar->GetCommandLevel() )
|
|
{
|
|
toSendTo->sysmessage( 1399 ); // You certainly cannot adjust those that are your betters!
|
|
return;
|
|
}
|
|
toSendTo->SetDWord( 7, targetChar->GetSerial() );
|
|
// Trigger scripted command
|
|
Commands->Command( toSendTo, targetChar, "tweak", true );
|
|
break;
|
|
default:
|
|
Console.error( " Fallout of switch statement without default. wholist.cpp, ButtonSelect()" );
|
|
break;
|
|
}
|
|
}
|
|
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Function - void Command( CSocket *toSendTo, UI08 type, UI16 buttonPressed )
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Purpose - Builds the WhoList gump and sends it to the player
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
void cWhoList::Command( CSocket *toSendTo, UI08 type, UI16 buttonPressed )
|
|
{
|
|
SERIAL serial = whoMenuData[buttonPressed];
|
|
CChar *targetChar = calcCharObjFromSer( serial ); // find selected char ...
|
|
|
|
if( !ValidateObject( targetChar ) )
|
|
{
|
|
toSendTo->sysmessage( 1387 );
|
|
return;
|
|
}
|
|
|
|
CPSendGumpMenu toSend;
|
|
toSend.UserID( INVALIDSERIAL );
|
|
toSend.GumpID( type );
|
|
|
|
UnicodeTypes sLang = toSendTo->Language();
|
|
UI16 lColour = cwmWorldState->ServerData()->LeftTextColour();
|
|
UI16 tColour = cwmWorldState->ServerData()->TitleColour();
|
|
UI16 butRight = cwmWorldState->ServerData()->ButtonRight();
|
|
//--static pages
|
|
toSend.addCommand( "page 0" );
|
|
toSend.addCommand( strutil::format("resizepic 0 0 %u 260 340", cwmWorldState->ServerData()->BackgroundPic()) );
|
|
toSend.addCommand( strutil::format("button 30 300 %u %i 1 0 1", cwmWorldState->ServerData()->ButtonCancel(), cwmWorldState->ServerData()->ButtonCancel() + 1)); //OKAY
|
|
toSend.addCommand( strutil::format("text 30 40 %u 0", tColour )); //text <Spaces from Left> <Space from top> <Length, Color?> <# in order>
|
|
toSend.addCommand( strutil::format("text 30 60 %u 1", tColour) );
|
|
toSend.addCommand( "page 1" );
|
|
|
|
toSend.addCommand( strutil::format("text 50 90 %u 2", lColour) ); //goto text
|
|
toSend.addCommand( strutil::format("text 50 110 %u 3", lColour) ); //gettext
|
|
toSend.addCommand( strutil::format("text 50 130 %u 4", lColour )); //Jail text
|
|
toSend.addCommand( strutil::format("text 50 150 %u 5", lColour )); //Release text
|
|
toSend.addCommand( strutil::format("text 50 170 %u 6", lColour )); //Kick user text
|
|
toSend.addCommand( strutil::format("text 50 190 %u 7", lColour ));
|
|
toSend.addCommand( strutil::format("text 50 210 %u 8", lColour ));
|
|
toSend.addCommand( strutil::format("text 50 230 %u 9", lColour) );
|
|
toSend.addCommand( strutil::format("text 50 270 %u 10", lColour ));
|
|
toSend.addCommand( strutil::format("button 20 90 %u %i 1 0 200", butRight, butRight + 1 )); //goto button
|
|
toSend.addCommand( strutil::format("button 20 110 %u %i 1 0 201", butRight, butRight + 1 )); //get button
|
|
toSend.addCommand( strutil::format("button 20 130 %u %i 1 0 202", butRight, butRight + 1 )); //Jail button
|
|
toSend.addCommand( strutil::format("button 20 150 %u %i 1 0 203", butRight, butRight + 1 )); //Release button
|
|
toSend.addCommand( strutil::format("button 20 170 %u %i 1 0 204", butRight, butRight + 1 )); //kick button
|
|
toSend.addCommand( strutil::format("button 20 190 %u %i 1 0 205", butRight, butRight + 1 )); //Where button
|
|
toSend.addCommand( strutil::format("button 20 210 %u %i 1 0 206", butRight, butRight + 1 )); //Cstats button
|
|
toSend.addCommand( strutil::format("button 20 230 %u %i 1 0 207", butRight, butRight + 1 )); //Tweak button
|
|
|
|
toSend.addText(strutil::format( "User %u selected (account %u)",buttonPressed, targetChar->GetAccount().wAccountIndex));
|
|
toSend.addText( strutil::format("Name: %s", targetChar->GetName().c_str() ));
|
|
toSend.addText( Dictionary->GetEntry( 1400, sLang ) );
|
|
toSend.addText( Dictionary->GetEntry( 1401, sLang ) );
|
|
toSend.addText( Dictionary->GetEntry( 1402, sLang ) );
|
|
toSend.addText( Dictionary->GetEntry( 1403, sLang ) );
|
|
toSend.addText( Dictionary->GetEntry( 1404, sLang ) );
|
|
toSend.addText( Dictionary->GetEntry( 1405, sLang ) );
|
|
toSend.addText( Dictionary->GetEntry( 1406, sLang ) );
|
|
toSend.addText( Dictionary->GetEntry( 1407, sLang ) );
|
|
toSend.addText( strutil::format("Serial#[%x %x %x %x]", targetChar->GetSerial( 1 ), targetChar->GetSerial( 2 ), targetChar->GetSerial( 3 ), targetChar->GetSerial( 4 )) );
|
|
|
|
toSend.Finalize();
|
|
toSendTo->Send( &toSend );
|
|
}
|
|
|
|
void cWhoList::ZeroWho( void )
|
|
{
|
|
FlagUpdate();
|
|
gmCount = 0;
|
|
}
|
|
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Function - void Update( void )
|
|
//| Date - 12th February, 2000
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
//| Purpose - If multiple GMs using, doesn't actually update (deferred update)
|
|
//| Otherwise updates the arrays, and resets the update flag
|
|
//|
|
|
//| Changes - 1.1 June 29th, 2000
|
|
//| Written to use SendVecsAsGump, as well as making it flexible enough to show offline players
|
|
//o-----------------------------------------------------------------------------------------------o
|
|
void cWhoList::Update( void )
|
|
{
|
|
if( gmCount > 1 )
|
|
{
|
|
return;
|
|
}
|
|
// do code
|
|
Delete();
|
|
constexpr std::uint16_t maxsize = 512 ;
|
|
|
|
size_t i = 0;
|
|
const UI32 numPerPage = 13;
|
|
UI32 pagenum = 1, position = 40, linenum = 1, buttonnum = 7;
|
|
|
|
size_t k = cwmWorldState->GetPlayersOnline();
|
|
SI32 realCount = 1;
|
|
//--static pages
|
|
one.push_back( "page 0" );
|
|
|
|
one.push_back( strutil::format(maxsize, "resizepic 0 0 %u 320 340", cwmWorldState->ServerData()->BackgroundPic() ) );
|
|
|
|
one.push_back( strutil::format(maxsize,"button 250 15 %u %i 1 0 1", cwmWorldState->ServerData()->ButtonCancel(), cwmWorldState->ServerData()->ButtonCancel() + 1 ) );
|
|
|
|
one.push_back( strutil::format(maxsize, "text 45 15 %u 0", cwmWorldState->ServerData()->TitleColour() ) );
|
|
|
|
|
|
one.push_back( strutil::format(maxsize, "page %u", pagenum ) );
|
|
|
|
|
|
two.push_back( "Wholist" );
|
|
|
|
//--Start User List
|
|
if( online )
|
|
{
|
|
for( i = 0; i < k; ++i )
|
|
{
|
|
CSocket *tSock = Network->GetSockPtr( static_cast<std::uint32_t>(i) );
|
|
CChar *tChar = tSock->CurrcharObj();
|
|
if( !ValidateObject( tChar ) )
|
|
continue;
|
|
if( realCount > 0 && !(realCount%numPerPage) )
|
|
{
|
|
position = 40;
|
|
++pagenum;
|
|
|
|
one.push_back( strutil::format(maxsize, "page %u", pagenum ) );
|
|
}
|
|
|
|
one.push_back( strutil::format(maxsize, "text 50 %u %u %u", position, cwmWorldState->ServerData()->LeftTextColour(), linenum ) );
|
|
|
|
one.push_back( strutil::format(maxsize,"button 20 %u %u %i %u 0 %u", position, cwmWorldState->ServerData()->ButtonRight(), cwmWorldState->ServerData()->ButtonRight() + 1, pagenum, buttonnum ) );
|
|
|
|
two.push_back( strutil::format(maxsize, " %s", tChar->GetName().c_str() ) );
|
|
AddSerial( tChar->GetSerial() );
|
|
|
|
position += 20;
|
|
++linenum;
|
|
++buttonnum;
|
|
++realCount;
|
|
}
|
|
|
|
|
|
two[0] = strutil::format(maxsize, "Wholist [%i online]", realCount - 1 );
|
|
|
|
pagenum = 1;
|
|
k = realCount;
|
|
for( i = 0; i < k; i += numPerPage )
|
|
{
|
|
|
|
one.push_back( strutil::format(maxsize, "page %u", pagenum ) );
|
|
if( i >= numPerPage )
|
|
{
|
|
//back button
|
|
one.push_back( strutil::format(maxsize, "button 50 300 %u %i 0 %i", cwmWorldState->ServerData()->ButtonLeft(), cwmWorldState->ServerData()->ButtonLeft() + 1, pagenum - 1 ) );
|
|
}
|
|
if( ( k > numPerPage ) && ( ( i + numPerPage ) < k ) )
|
|
{
|
|
|
|
one.push_back( strutil::format(maxsize, "button 260 300 %u %i 0 %i", cwmWorldState->ServerData()->ButtonRight(), cwmWorldState->ServerData()->ButtonRight() + 1, pagenum + 1 ) );
|
|
}
|
|
++pagenum;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MAPUSERNAMEID_ITERATOR I;
|
|
//
|
|
CChar *ourChar = nullptr;
|
|
for( I = Accounts->begin(); I != Accounts->end(); ++I )
|
|
{
|
|
CAccountBlock& actbSearch = I->second;
|
|
//
|
|
for( i = 0; i < 7; ++i )
|
|
{
|
|
ourChar = actbSearch.lpCharacters[i];
|
|
if( ValidateObject( ourChar ) )
|
|
{
|
|
if( !isOnline( (*ourChar) ) )
|
|
{
|
|
if( realCount > 0 && !(realCount%numPerPage) )
|
|
{
|
|
position = 40;
|
|
++pagenum;
|
|
|
|
one.push_back( strutil::format(maxsize,"page %u", pagenum ) );
|
|
}
|
|
|
|
one.push_back( strutil::format(maxsize, "text 50 %u %u %u", position, cwmWorldState->ServerData()->LeftTextColour(), linenum ) );
|
|
|
|
one.push_back( strutil::format(maxsize,"button 20 %u %u %i %u 0 %u", position, cwmWorldState->ServerData()->ButtonRight(), cwmWorldState->ServerData()->ButtonRight() + 1, pagenum, buttonnum ) );
|
|
|
|
|
|
two.push_back( strutil::format(maxsize," %s (%s)", ourChar->GetName().c_str(), ourChar->GetLastOn().c_str() ) );
|
|
AddSerial( ourChar->GetSerial() );
|
|
|
|
position += 20;
|
|
++linenum;
|
|
++buttonnum;
|
|
++realCount;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
two[0] = strutil::format(maxsize,"Wholist [%i offline]", realCount-1 );
|
|
|
|
pagenum = 1;
|
|
k = realCount;
|
|
for( i = 0; i < k; i += numPerPage )
|
|
{
|
|
|
|
one.push_back( strutil::format(maxsize,"page %u", pagenum ) );
|
|
if( i >= numPerPage )
|
|
{
|
|
//back button
|
|
one.push_back( strutil::format(maxsize, "button 50 300 %u %i 0 %i", cwmWorldState->ServerData()->ButtonLeft(), cwmWorldState->ServerData()->ButtonLeft() + 1, pagenum - 1 ) );
|
|
}
|
|
if( ( k > numPerPage ) && ( ( i + numPerPage ) < k ) )
|
|
{
|
|
one.push_back( strutil::format(maxsize,"button 260 300 %u %i 0 %i", cwmWorldState->ServerData()->ButtonRight(), cwmWorldState->ServerData()->ButtonRight() + 1, pagenum + 1 ) );
|
|
}
|
|
++pagenum;
|
|
}
|
|
}
|
|
ResetUpdateFlag();
|
|
}
|