Save deposit state

--HG--
branch : save_deposit_state_v2
This commit is contained in:
Guillaume Dupuy 2017-04-12 20:02:11 +02:00
parent a1fbc963a9
commit bd3a27778e
6 changed files with 200 additions and 7 deletions

View file

@ -36,6 +36,7 @@
#include "game_share/multi_target.h" #include "game_share/multi_target.h"
#include "phrase_manager/s_effect.h" #include "phrase_manager/s_effect.h"
#include "projectile_stats.h" #include "projectile_stats.h"
#include "primitives_parser.h"
using namespace std; using namespace std;
using namespace NLMISC; using namespace NLMISC;
@ -293,11 +294,10 @@ struct TCompareStaticItemPtrBySheetId : public std::binary_function<CStaticItem*
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Parse primitive file for one deposit // Parse primitive file for one deposit
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool CDeposit::build( const NLLIGO::CPrimZone* zone ) bool CDeposit::build( const NLLIGO::CPrimZone* zone)
{ {
if ( IsRingShard ) if ( IsRingShard )
return false; return false;
//_Id =id; //_Id =id;
*( (NLLIGO::CPrimZone*)this ) = *zone; *( (NLLIGO::CPrimZone*)this ) = *zone;
@ -305,7 +305,11 @@ bool CDeposit::build( const NLLIGO::CPrimZone* zone )
string name; string name;
if ( ! zone->getPropertyByName( "name", name ) ) return malformed( "name", name ); if ( ! zone->getPropertyByName( "name", name ) ) return malformed( "name", name );
_Name = name; _Name = name;
// Read alias
if(!CPrimitivesParser::getAlias(zone, _Alias))
{
nlwarning("<CDeposit::build> Could not find an alias for deposit %s", _Name.c_str());
}
// Read exact raw material codes to add // Read exact raw material codes to add
vector<string> *exactRMCodesS = NULL; vector<string> *exactRMCodesS = NULL;
if ( ! (zone->getPropertyByName( "exact_mp_item", exactRMCodesS ) && exactRMCodesS) ) return malformed( "exact_mp_item", name ); if ( ! (zone->getPropertyByName( "exact_mp_item", exactRMCodesS ) && exactRMCodesS) ) return malformed( "exact_mp_item", name );
@ -469,6 +473,21 @@ bool CDeposit::build( const NLLIGO::CPrimZone* zone )
return true; return true;
} }
CDepositState CDeposit::currentState()
{
CDepositState out;
//If we don't have an alias, don't send any information (it's better to be missing information than having wrong information)
if(_Alias == 0)
return out;
// We should never save the state of a spot without quantity constraint, this is just an additional safeguard against it
if(!_QuantityConstraintsPt)
return out;
out.alias = _Alias;
out.currentQuantity = _QuantityConstraintsPt->getCurrentQuantity();
out.nextRespawnDay = _QuantityConstraintsPt->NextRespawnDay;
return out;
}
/* /*
* Select the raw materials, using the specified filters and _Ecotype * Select the raw materials, using the specified filters and _Ecotype

View file

@ -195,6 +195,28 @@ namespace NLMISC
class CWordsDictionary; class CWordsDictionary;
} }
struct CDepositState {
uint32 alias;
float currentQuantity;
uint32 nextRespawnDay;
void serial(NLMISC::IStream &f) throw(NLMISC::EStream)
{
if(f.isXML())
{
f.xmlSerial(alias, "ALIAS");
f.xmlSerial(currentQuantity, "CURRENT_QUANTITY");
f.xmlSerial(nextRespawnDay, "NEXT_RESPAWN_DAY");
}
else
{
f.serial(alias);
f.serial(currentQuantity);
f.serial(nextRespawnDay);
}
}
};
/** /**
* \author Nicolas Brigand, Alain Saffray, Olivier Cado * \author Nicolas Brigand, Alain Saffray, Olivier Cado
* \author Nevrax France * \author Nevrax France
@ -205,7 +227,7 @@ class CDeposit : public NLLIGO::CPrimZone, public NLMISC::CRefCount
public: public:
/// Constructor /// Constructor
CDeposit() : _AutoSpawnSourcePt(NULL), _QuantityConstraintsPt(NULL), _Ecotype(ECOSYSTEM::common_ecosystem), _FilterPhase(0), _KamiAnger(0.0f), _MinQuality(-1), _MaxQuality(-1), _SourceFXIndex(0), _CanProspect(false), _Enabled(false), _CurrentNbAutoSpawnedSources(0), _AllowDepletionRisk(true) {} CDeposit() : _AutoSpawnSourcePt(NULL), _QuantityConstraintsPt(NULL), _Ecotype(ECOSYSTEM::common_ecosystem), _FilterPhase(0), _KamiAnger(0.0f), _MinQuality(-1), _MaxQuality(-1), _SourceFXIndex(0), _CanProspect(false), _Enabled(false), _CurrentNbAutoSpawnedSources(0), _AllowDepletionRisk(true), _Alias(0) {}
/// Destructor /// Destructor
~CDeposit(); ~CDeposit();
@ -214,7 +236,7 @@ public:
static void addEcotype( CEcotypeZone *ecotypeZone ) { _EcotypeZones.push_back( ecotypeZone ); } static void addEcotype( CEcotypeZone *ecotypeZone ) { _EcotypeZones.push_back( ecotypeZone ); }
/// Init deposit /// Init deposit
bool build( const NLLIGO::CPrimZone* zone ); bool build(const NLLIGO::CPrimZone* zone );
/// Clear all ecotype information, after having built the deposits /// Clear all ecotype information, after having built the deposits
static void clearEcotypes(); static void clearEcotypes();
@ -319,7 +341,7 @@ public:
float getMaxQuantity() { return _QuantityConstraintsPt ? _QuantityConstraintsPt->getCurrentQuantity() : FLT_MAX; } float getMaxQuantity() { return _QuantityConstraintsPt ? _QuantityConstraintsPt->getCurrentQuantity() : FLT_MAX; }
/// Consume. Return the actual consumed quantity (may be lower if there is no more to get) /// Consume. Return the actual consumed quantity (may be lower if there is no more to get)
float consumeQuantity( float requested ) { if ( _QuantityConstraintsPt ) return _QuantityConstraintsPt->consumeQuantity( requested ); else return requested; } float consumeQuantity( float requested ) { if ( _QuantityConstraintsPt )return _QuantityConstraintsPt->consumeQuantity( requested ); else return requested; }
/** /**
* Get a random RM from the neighbourhood of the specified position. * Get a random RM from the neighbourhood of the specified position.
@ -346,6 +368,13 @@ public:
// For auto-spawn source minimum number. Internaly used by CHarvestSource only // For auto-spawn source minimum number. Internaly used by CHarvestSource only
void decreaseAutoSpawnedSources(); void decreaseAutoSpawnedSources();
void increaseAutoSpawnedSources(); void increaseAutoSpawnedSources();
/// Used to save the deposit
bool needSave() const { return _QuantityConstraintsPt && (_QuantityConstraintsPt->CurrentQuantity != _QuantityConstraintsPt->InitialQuantity || _QuantityConstraintsPt->NextRespawnDay != 0); }
CDepositState currentState();
uint32 getAlias() const { return _Alias;}
void setCurrentQuantity(uint32 currentQuantity) { _QuantityConstraintsPt->CurrentQuantity = currentQuantity; }
void setNextRespawnDay(uint32 nextRespawnDay) { _QuantityConstraintsPt->NextRespawnDay = nextRespawnDay; }
protected: protected:
@ -429,6 +458,9 @@ private:
/// Current Number of AutoSpawned Sources in this deposit /// Current Number of AutoSpawned Sources in this deposit
uint32 _CurrentNbAutoSpawnedSources; uint32 _CurrentNbAutoSpawnedSources;
/// CPrimAlias, needed to identify a deposit to restore its state between shutdown of the EGS
uint32 _Alias;
}; };

View file

@ -329,6 +329,10 @@ CVariable<float> DodgeFactorForForageSkills("egs","DodgeFactorForForageSkills"
CVariable<float> ForageExtractionTimeMinGC( "egs", "ForageExtractionTimeMinGC", "Minimum time of extraction in ticks", 230.0f, 0, true ); CVariable<float> ForageExtractionTimeMinGC( "egs", "ForageExtractionTimeMinGC", "Minimum time of extraction in ticks", 230.0f, 0, true );
CVariable<float> ForageExtractionTimeSlopeGC( "egs", "ForageExtractionTimeSlopeGC", "Slope of base extraction time curve", 2.0f, 0, true ); CVariable<float> ForageExtractionTimeSlopeGC( "egs", "ForageExtractionTimeSlopeGC", "Slope of base extraction time curve", 2.0f, 0, true );
CVariable<bool> RefillDepositOnStartup("egs", "RefillDepositOnStartup", "Ignore saved CurrentQuantity / NextRespawnDay in deposits", false, 0, true);
CVariable<uint32> DepositSaveInterval("egs", "DepositSaveInterval", "time *in tick* between two saves of a deposit", 10 * 60 * 10, 0, true);
CVariable<bool> DepositStateUseXml("egs", "DepositStateUseXml", "Use xml instead of binary file to save deposit state", true, 0, true);
CVariable<float> ForageQuantityBaseRate( "egs", "ForageQuantityBaseRate", "Base of extraction rate", 0.23f, 0, true ); // 0.23 doubles the previous minimum setting CVariable<float> ForageQuantityBaseRate( "egs", "ForageQuantityBaseRate", "Base of extraction rate", 0.23f, 0, true ); // 0.23 doubles the previous minimum setting

View file

@ -280,6 +280,9 @@ extern NLMISC::CVariable<float> ForageQuantityXPDeltaLevelBonusRate;
extern NLMISC::CVariable<float> ForageExtractionTimeMinGC; extern NLMISC::CVariable<float> ForageExtractionTimeMinGC;
extern NLMISC::CVariable<float> ForageExtractionTimeSlopeGC; extern NLMISC::CVariable<float> ForageExtractionTimeSlopeGC;
extern NLMISC::CVariable<bool> RefillDepositOnStartup;
extern NLMISC::CVariable<uint32> DepositSaveInterval;
extern NLMISC::CVariable<bool> DepositStateUseXml;
// QUARTERING // QUARTERING
extern NLMISC::CVariable<float> QuarteringQuantityAverageForCraftHerbivore; extern NLMISC::CVariable<float> QuarteringQuantityAverageForCraftHerbivore;

View file

@ -530,8 +530,9 @@ void CZoneManager::release()
void CZoneManager::initInstance() void CZoneManager::initInstance()
{ {
_NextDepositIndexUpdated = 0; _NextDepositIndexUpdated = 0;
_NextDepositSave = CTickEventHandler::getGameCycle() + DepositSaveInterval;
_SpreadUpdateLoopBeginTick = CTickEventHandler::getGameCycle(); _SpreadUpdateLoopBeginTick = CTickEventHandler::getGameCycle();
// get the loaded primitives // get the loaded primitives
const CPrimitivesParser::TPrimitivesList & primsList = CPrimitivesParser::getInstance().getPrimitives(); const CPrimitivesParser::TPrimitivesList & primsList = CPrimitivesParser::getInstance().getPrimitives();
@ -589,6 +590,8 @@ void CZoneManager::initInstance()
nlwarning("<CZoneManager constructor> Error while building the zones"); nlwarning("<CZoneManager constructor> Error while building the zones");
} }
} }
// Ask Bsi for saved deposit states
Bsi.requestFile(DepositStateFileName, new CDepositCallback());
// Don't keep ecotypes in memory, the information is already in the deposits // Don't keep ecotypes in memory, the information is already in the deposits
CDeposit::clearEcotypes(); CDeposit::clearEcotypes();
@ -1417,6 +1420,59 @@ bool CZoneManager::parsePVPSafeZones( const NLLIGO::IPrimitive * prim )
return result; return result;
} // CZoneManager parsePVPSafeZones } // CZoneManager parsePVPSafeZones
//-----------------------------------------------
// CZoneManager receivedDepositState
//-----------------------------------------------
void CZoneManager::receivedDepositState(const CFileDescription& fileDescription, NLMISC::IStream& dataStream)
{
if(fileDescription.FileName.empty())
{
nlwarning("Got no deposit state file from backup service, probably because no deposit need to be saved");
return;
}
NLMISC::CMemStream& memStream = dynamic_cast<NLMISC::CMemStream&>(dataStream);
if (&memStream != NULL)
{
try
{
std::vector<CDepositState> states;
if(DepositStateUseXml)
{
CIXml xml;
xml.init(memStream);
xml.serialCont(states);
}
else
{
memStream.serialCont(states);
}
nldebug("Got %d CDepositState from backup service", states.size());
//If we don't want to use state, stop here
if(RefillDepositOnStartup) return;
for(int i=0; i < states.size(); i++)
{
//Find the matching deposit
for(int j = 0 ; j < _Deposits.size(); j++)
{
CDeposit* dep = _Deposits[j];
if(dep->getAlias() == states[i].alias)
{
dep->setCurrentQuantity(states[i].currentQuantity);
dep->setNextRespawnDay(states[i].nextRespawnDay);
}
}
nldebug("CDepositState for alias %d : currentQuantity=%f, nextRespawn=%d", states[i].alias, states[i].currentQuantity, states[i].nextRespawnDay);
}
}
catch (const Exception& e)
{
nlwarning("Could not parse deposit state file, reason : %s", e.what());
}
}
}// CZoneManager receivedDepositState
//----------------------------------------------- //-----------------------------------------------
// CZoneManager getContinent // CZoneManager getContinent
//----------------------------------------------- //-----------------------------------------------
@ -2021,9 +2077,63 @@ void CZoneManager::tickUpdate()
_DepositNeedingAutoSpawnUpdate.erase(itDeposit); _DepositNeedingAutoSpawnUpdate.erase(itDeposit);
itDeposit= itNext; itDeposit= itNext;
} }
// Save the deposits
if(_NextDepositSave < CTickEventHandler::getGameCycle())
{
_NextDepositSave = CTickEventHandler::getGameCycle() + DepositSaveInterval;
saveDeposits();
}
}// CZoneManager tickUpdate }// CZoneManager tickUpdate
//-----------------------------------------------
// CZoneManager saveDeposits
//-----------------------------------------------
void CZoneManager::saveDeposits()
{
std::vector<CDepositState> toSave;
for(int i=0; i < _Deposits.size(); i++)
{
if (!_Deposits[i]->needSave()) continue;
CDepositState tmp = _Deposits[i]->currentState();
//Don't save if for some reason we couldn't get an alias for the deposit
if(tmp.alias == 0) continue;
toSave.push_back(tmp);
}
// No need to save if we have 0 states
if(toSave.size() == 0) return;
CMemStream stream;
try
{
if(DepositStateUseXml)
{
COXml output;
if (!output.init(&stream))
{
nlwarning("<CZoneManager::saveDeposits> cannot init XML output for file %s", DepositStateFileName.c_str());
return;
}
output.serialCont(toSave);
output.flush();
}
else
{
stream.serialCont(toSave);
}
}
catch (const Exception & e)
{
nlwarning("<CZoneManager::saveDeposits> cannot save file %s : %s", DepositStateFileName.c_str(), e.what());
}
nldebug("<CZoneManager::saveDeposits>: sending %d states to BIS (total of %d deposits available).", toSave.size(), _Deposits.size());
CBackupMsgSaveFile msg( DepositStateFileName, CBackupMsgSaveFile::SaveFile, Bsi );
msg.DataMsg.serialBuffer((uint8*)stream.buffer(), stream.length());
Bsi.sendFile( msg );
}// CZoneManager saveDeposits
//----------------------------------------------- //-----------------------------------------------
// CZoneManager dumpWorld // CZoneManager dumpWorld
//----------------------------------------------- //-----------------------------------------------

View file

@ -31,6 +31,7 @@
#include "game_share/string_manager_sender.h" #include "game_share/string_manager_sender.h"
#include "mission_manager/ai_alias_translator.h" #include "mission_manager/ai_alias_translator.h"
#include "deposit.h" #include "deposit.h"
#include "game_share/backup_service_interface.h"
class CCharacter; class CCharacter;
extern NLMISC::CRandom RandomGenerator; extern NLMISC::CRandom RandomGenerator;
@ -39,6 +40,7 @@ static const uint16 InvalidSpawnZoneId = 0xFFFF;
static const uint16 InvalidPlaceId = 0xFFFF; static const uint16 InvalidPlaceId = 0xFFFF;
static const std::string DepositStateFileName = "deposits_state";
/** /**
* A teleport destination zone * A teleport destination zone
* \author Nicolas Brigand * \author Nicolas Brigand
@ -539,6 +541,11 @@ public:
*/ */
void clearEcotypes(); void clearEcotypes();
// Save deposit to primitive file, if needed
void saveDeposits();
/// Callback for deposit state
void receivedDepositState(CFileDescription const &fileDescription, NLMISC::IStream &dataStream);
private: private:
/** /**
@ -640,6 +647,24 @@ private:
/// The ecotype zones /// The ecotype zones
static CEcotypeZones _EcotypeZones; static CEcotypeZones _EcotypeZones;
/// Next cycle where we'll save deposits
NLMISC::TGameCycle _NextDepositSave;
};
class CDepositCallback : public IBackupFileReceiveCallback
{
public:
CDepositCallback() : processed(false) {}
bool processed;
void callback(const CFileDescription& fileDescription, NLMISC::IStream& dataStream)
{
if (!processed)
{
CZoneManager::getInstance().receivedDepositState(fileDescription, dataStream);
processed = true;
}
}
}; };