mirror of
https://github.com/polserver/polserver
synced 2026-08-13 08:23:08 -04:00
* origin/master: (93 commits) Add support for dictionary creation (#277) Add do-while statement (#276) Add foreach loops (#275) New compiler: array initialization (#274) Disambiguator: figure out if label is a case statement dispatch selector, or should apply to a statement within the case dispatch group's block. (#273) New compiler: Add support for case statements (#272) Change "logical" to "bitwise". (#258) Fix divide-by-zero errors, and mask FormatError if it were thrown in a destructor. (#271) Add break and continue statements. (#270) New compiler: assignment to local and global variables. (#269) Add support for while loops (#268) Optimize if statements, and emit module functions in legacy order (#267) Optimizations: binary operators (#266) Add binary operators (#265) Add support for const declarations (#264) Handle default parameter values, pass-by-name, and return statements in functions. (#263) Add limited support for user functions (#262) New compiler: add return and exit statements (#261) Add support for if-then-else statements (#259) OG compiler: set module to Mod_Basic when a token is an identifier (#257) ...
280 lines
8.1 KiB
C++
280 lines
8.1 KiB
C++
/** @file
|
|
*
|
|
* @par History
|
|
* - 2005/01/23 Shinigami: decay_items & decay_thread - Tokuno MapDimension doesn't fit blocks of
|
|
* 64x64 (WGRID_SIZE)
|
|
* - 2010/03/28 Shinigami: Transmit Pointer as Pointer and not Int as Pointer within
|
|
* decay_thread_shadow
|
|
*/
|
|
|
|
// it could be completely rewritten with area, but to lazy and decay should be handled anyway in
|
|
// another way
|
|
#include "decay.h"
|
|
|
|
#include <stddef.h>
|
|
|
|
#include "../clib/esignal.h"
|
|
#include "../clib/logfacility.h"
|
|
#include "../plib/systemstate.h"
|
|
#include "gameclck.h"
|
|
#include "globals/state.h"
|
|
#include "globals/uvars.h"
|
|
#include "item/item.h"
|
|
#include "item/itemdesc.h"
|
|
#include "polcfg.h"
|
|
#include "polsem.h"
|
|
#include "realms/realm.h"
|
|
#include "scrdef.h"
|
|
#include "scrsched.h"
|
|
#include "syshook.h"
|
|
#include "ufunc.h"
|
|
#include "uoscrobj.h"
|
|
#include "uworld.h"
|
|
|
|
|
|
namespace Pol
|
|
{
|
|
namespace Core
|
|
{
|
|
///
|
|
/// [1] Item Decay Criteria
|
|
/// An Item is allowed to decay if ALL of the following are true:
|
|
/// - it is not In Use
|
|
/// - it is Movable, OR it is a Corpse
|
|
/// - its 'decayat' member is nonzero
|
|
/// AND the Game Clock has passed this 'decayat' time
|
|
/// - it is not supported by a multi,
|
|
/// OR its itemdesc.cfg entry specifies 'DecaysOnMultis 1'
|
|
/// - it itemdesc.cfg entry specifies no 'DestroyScript',
|
|
/// OR its 'DestroyScript' returns nonzero.
|
|
///
|
|
/// [2] Decay Action
|
|
/// Container contents are moved to the ground at the Container's location
|
|
/// before destroying the container.
|
|
///
|
|
|
|
void decay_worldzone( const Pos2d& pos, Realms::Realm* realm )
|
|
{
|
|
Zone& zone = realm->getzone( pos );
|
|
gameclock_t now = read_gameclock();
|
|
bool statistics = Plib::systemstate.config.thread_decay_statistics;
|
|
|
|
for ( ZoneItems::size_type idx = 0; idx < zone.items.size(); ++idx )
|
|
{
|
|
Items::Item* item = zone.items[idx];
|
|
if ( statistics )
|
|
{
|
|
if ( item->can_decay() )
|
|
{
|
|
const Items::ItemDesc& descriptor = item->itemdesc();
|
|
if ( !descriptor.decays_on_multis )
|
|
{
|
|
Multi::UMulti* multi = item->supporting_multi();
|
|
if ( multi == nullptr )
|
|
stateManager.decay_statistics.temp_count_active++;
|
|
}
|
|
else
|
|
stateManager.decay_statistics.temp_count_active++;
|
|
}
|
|
}
|
|
if ( item->should_decay( now ) )
|
|
{
|
|
// check the CanDecay syshook first if it returns 1 go over to other checks
|
|
if ( gamestate.system_hooks.can_decay )
|
|
{
|
|
if ( !gamestate.system_hooks.can_decay->call( new Module::EItemRefObjImp( item ) ) )
|
|
continue;
|
|
}
|
|
|
|
const Items::ItemDesc& descriptor = item->itemdesc();
|
|
Multi::UMulti* multi = item->supporting_multi();
|
|
|
|
// some things don't decay on multis:
|
|
if ( multi != nullptr && !descriptor.decays_on_multis )
|
|
continue;
|
|
|
|
if ( statistics )
|
|
stateManager.decay_statistics.temp_count_decayed++;
|
|
|
|
if ( !descriptor.destroy_script.empty() && !item->inuse() )
|
|
{
|
|
bool decayok = call_script( descriptor.destroy_script, item->make_ref() );
|
|
if ( !decayok )
|
|
continue;
|
|
}
|
|
|
|
item->spill_contents( multi );
|
|
destroy_item( item );
|
|
--idx;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
///
|
|
/// [3] Decay Sweep
|
|
/// Each 64x64 tile World Zone is checked for decay approximately
|
|
/// once every 10 minutes
|
|
///
|
|
|
|
void decay_single_zone( Realms::Realm* realm, const Pos2d& gridsize, Pos2d& pos )
|
|
{
|
|
pos += Vec2d( 1, 0 );
|
|
if ( pos.x() >= gridsize.x() )
|
|
{
|
|
pos.x( 0 );
|
|
pos += Vec2d( 0, 1 );
|
|
if ( pos.y() >= gridsize.y() )
|
|
{
|
|
pos.y( 0 );
|
|
}
|
|
}
|
|
decay_worldzone( pos, realm );
|
|
}
|
|
|
|
void decay_thread( void* arg ) // Realm*
|
|
{
|
|
Pos2d pos( 0, 0 );
|
|
Realms::Realm* realm = static_cast<Realms::Realm*>( arg );
|
|
|
|
Pos2d gridsize( realm->grid_width(), realm->grid_height() );
|
|
|
|
unsigned sleeptime = ( 60 * 10L * 1000 ) / ( gridsize.x() * gridsize.y() );
|
|
while ( !Clib::exit_signalled )
|
|
{
|
|
{
|
|
PolLock lck;
|
|
polclock_checkin();
|
|
decay_single_zone( realm, gridsize, pos );
|
|
restart_all_clients();
|
|
}
|
|
// sweep entire world every 10 minutes
|
|
// (60 * 10 * 1000) / (96 * 64) -> (600000 / 6144) -> 97 ms
|
|
|
|
pol_sleep_ms( sleeptime );
|
|
}
|
|
}
|
|
|
|
void decay_thread_shadow( void* arg ) // Realm*
|
|
{
|
|
Pos2d pos( 0, 0 );
|
|
unsigned id = static_cast<Realms::Realm*>( arg )->shadowid;
|
|
|
|
if ( gamestate.shadowrealms_by_id[id] == nullptr )
|
|
return;
|
|
Pos2d gridsize( gamestate.shadowrealms_by_id[id]->grid_width(),
|
|
gamestate.shadowrealms_by_id[id]->grid_height() );
|
|
|
|
unsigned sleeptime = ( 60 * 10L * 1000 ) / ( gridsize.x() * gridsize.y() );
|
|
while ( !Clib::exit_signalled )
|
|
{
|
|
{
|
|
PolLock lck;
|
|
polclock_checkin();
|
|
if ( gamestate.shadowrealms_by_id[id] == nullptr ) // is realm still there?
|
|
break;
|
|
decay_single_zone( gamestate.shadowrealms_by_id[id], gridsize, pos );
|
|
restart_all_clients();
|
|
}
|
|
// sweep entire world every 10 minutes
|
|
// (60 * 10 * 1000) / (96 * 64) -> (600000 / 6144) -> 97 ms
|
|
|
|
pol_sleep_ms( sleeptime );
|
|
}
|
|
}
|
|
|
|
bool should_switch_realm( size_t index, const Pos2d& pos, Pos2d* gridsize )
|
|
{
|
|
if ( index >= gamestate.Realms.size() )
|
|
return true;
|
|
Realms::Realm* realm = gamestate.Realms[index];
|
|
if ( realm == nullptr )
|
|
return true;
|
|
|
|
*gridsize = Pos2d( realm->grid_width(), realm->grid_height() );
|
|
|
|
// check if ++y would result in reset
|
|
if ( pos.y() + 1 >= gridsize->y() )
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
void decay_single_thread( void* arg )
|
|
{
|
|
(void)arg;
|
|
// calculate total grid count, based on current realms
|
|
unsigned total_grid_count = 0;
|
|
for ( const auto& realm : gamestate.Realms )
|
|
{
|
|
total_grid_count += ( realm->grid_width() * realm->grid_height() );
|
|
}
|
|
if ( !total_grid_count )
|
|
{
|
|
POLLOG_ERROR << "No realm grids?!\n";
|
|
return;
|
|
}
|
|
// sweep every realm ~10minutes -> 36ms for 6 realms
|
|
unsigned sleeptime = ( 60 * 10L * 1000 ) / total_grid_count;
|
|
sleeptime = std::min( std::max( sleeptime, 30u ), 500u ); // limit to 30ms-500ms
|
|
bool init = true;
|
|
size_t realm_index = ~0u;
|
|
Pos2d pos( 0, 0 );
|
|
Pos2d gridsize( 0, 0 );
|
|
while ( !Clib::exit_signalled )
|
|
{
|
|
{
|
|
PolLock lck;
|
|
polclock_checkin();
|
|
// check if realm_index is still valid and if y is still in valid range
|
|
if ( should_switch_realm( realm_index, pos, &gridsize ) )
|
|
{
|
|
++realm_index;
|
|
if ( realm_index >= gamestate.Realms.size() )
|
|
{
|
|
realm_index = 0;
|
|
if ( !init && Plib::systemstate.config.thread_decay_statistics )
|
|
{
|
|
stateManager.decay_statistics.decayed.update(
|
|
stateManager.decay_statistics.temp_count_decayed );
|
|
stateManager.decay_statistics.active_decay.update(
|
|
stateManager.decay_statistics.temp_count_active );
|
|
stateManager.decay_statistics.temp_count_decayed = 0;
|
|
stateManager.decay_statistics.temp_count_active = 0;
|
|
POLLOG_INFO.Format(
|
|
"DECAY STATISTICS: decayed: max {} mean {} variance {} runs {} active max {} mean "
|
|
"{} variance {} runs {}\n" )
|
|
<< stateManager.decay_statistics.decayed.max()
|
|
<< stateManager.decay_statistics.decayed.mean()
|
|
<< stateManager.decay_statistics.decayed.variance()
|
|
<< stateManager.decay_statistics.decayed.count()
|
|
<< stateManager.decay_statistics.active_decay.max()
|
|
<< stateManager.decay_statistics.active_decay.mean()
|
|
<< stateManager.decay_statistics.active_decay.variance()
|
|
<< stateManager.decay_statistics.active_decay.count();
|
|
}
|
|
init = false;
|
|
}
|
|
pos.x( 0 ).y( 0 );
|
|
}
|
|
else
|
|
{
|
|
pos += Vec2d( 1, 0 );
|
|
if ( pos.x() >= gridsize.x() )
|
|
{
|
|
pos.x( 0 );
|
|
pos += Vec2d( 0, 1 );
|
|
if ( pos.y() >= gridsize.y() )
|
|
{
|
|
POLLOG_ERROR << "SHOULD NEVER HAPPEN\n";
|
|
pos.y( 0 );
|
|
}
|
|
}
|
|
}
|
|
decay_worldzone( pos, gamestate.Realms[realm_index] );
|
|
restart_all_clients();
|
|
}
|
|
pol_sleep_ms( sleeptime );
|
|
}
|
|
}
|
|
} // namespace Core
|
|
} // namespace Pol
|