// Ryzom - MMORPG Framework
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
#include "stdpch.h"
#include "nel/ligo/primitive.h"
#include "nel/ligo/ligo_config.h"
#include "game_share/tick_event_handler.h"
#include "game_share/ryzom_version.h"
#include "world_container.h"
#include "ai.h"
#include "ai_mgr.h"
#include "ai_keywords.h"
#include "mirrors.h"
#include "messages.h"
#include "ais_actions.h"
#include "egs_interface.h"
#include "aids_interface.h"
#include "game_share/fame.h"
#include "visual_properties_interface.h"
#include "ais_user_models.h"
#ifdef NL_OS_WINDOWS
# ifndef NL_COMP_MINGW
# define NOMINMAX
# endif
# include
#endif // NL_OS_WINDOWS
//#include "nel/misc/bitmap.h"
using namespace NLMISC;
using namespace NLNET;
using namespace std;
// force admin module to link in
extern void admin_modules_forceLink();
void foo()
{
admin_modules_forceLink();
}
bool EGSHasMirrorReady = false;
bool IOSHasMirrorReady = false;
// The ligo config
NLLIGO::CLigoConfig LigoConfig;
namespace AICOMP
{
bool compileExternalScript (const char *filename, const char *outputFilename);
}
/*-----------------------------------------------------------------*\
SERVICE CLASS
\*-----------------------------------------------------------------*/
class CAIService : public NLNET::IService
{
public:
void commandStart();
void init();
bool update();
void release();
void tickRelease();
};
// callback for the 'tick' update message
void cbTick();
// callback for the 'tick' release message
void cbTickRelease()
{
(static_cast(CAIService::getInstance()))->tickRelease();
}
/*-----------------------------------------------------------------*\
SERVICE INIT & RELEASE
\*-----------------------------------------------------------------*/
static void cbServiceMirrorUp( const std::string& serviceName, NLNET::TServiceId serviceId, void * )
{
if (serviceName == "IOS")
{
IOSHasMirrorReady = true;
}
if (serviceName == "EGS")
{
EGSHasMirrorReady = true;
// force an AI update on EGS up
CAIS::instance().update();
//send custom data to EGS
CAIUserModelManager::getInstance()->sendUserModels();
CAIUserModelManager::getInstance()->sendCustomLootTables();
}
CAIS::instance().serviceEvent(CServiceEvent(serviceId, serviceName, CServiceEvent::SERVICE_UP));
}
static void cbServiceDown( const std::string& serviceName, NLNET::TServiceId serviceId, void * )
{
if ( serviceName == "IOS" )
{
IOSHasMirrorReady = false;
}
if ( serviceName == "EGS" )
{
EGSHasMirrorReady = false;
}
CAIS::instance().serviceEvent(CServiceEvent(serviceId, serviceName, CServiceEvent::SERVICE_DOWN));
}
void CAIService::commandStart()
{
// Compile an AI script ?
if (haveArg ('c'))
{
string scriptFilename = getArg ('c');
bool result = false;
if (!scriptFilename.empty ())
{
string outputFilename;
if (haveArg ('o'))
outputFilename = getArg ('o');
// Compile and exit
result = AICOMP::compileExternalScript (scriptFilename.c_str (), outputFilename.c_str ());
}
else
nlwarning ("No script filename");
::exit (result?0:-1);
}
}
///init
void CAIService::init (void)
{
// start any available system command.
CConfigFile::CVar *sysCmds = IService::getInstance()->ConfigFile.getVarPtr("SystemCmd");
if (sysCmds != NULL)
{
for (uint i=0; isize(); ++i)
{
string cmd = sysCmds->asString(i);
nlinfo("Invoking system command '%s'...", cmd.c_str());
int ret = system(cmd.c_str());
nlinfo(" command returned %d", ret);
}
}
// read sheet_id.bin and don't prune out unknown files
CSheetId::init(false);
// Init singleton manager
CSingletonRegistry::getInstance()->init();
// init static fame manager
CStaticFames::getInstance();
setVersion (RYZOM_VERSION);
// Init ligo
if (!LigoConfig.readPrimitiveClass ("world_editor_classes.xml", false))
{
// Should be in l:\leveldesign\world_editor_files
nlerror ("Can't load ligo primitive config file world_editor_classes.xml");
}
// have ligo library register its own class types for its class factory
NLLIGO::Register();
// setup the update systems
setUpdateTimeout(100);
// init sub systems
CAIKeywords::init();
CMirrors::init(cbTick, NULL, cbTickRelease);
CMessages::init();
AISHEETS::CSheets::getInstance()->init();
// initialise the AI_SHARE library
AI_SHARE::init(&LigoConfig);
// set the primitive context
NLLIGO::CPrimitiveContext::instance().CurrentLigoConfig = &LigoConfig;
CAISActions::init();
CEGSInterface::init();
CTimeInterface::init();
CCombatInterface::init();
CVisualPropertiesInterface::init();
CAIDSInterface::init();
// register the service up and service down callbacks
CMirrors::Mirror.setServiceMirrorUpCallback("*", cbServiceMirrorUp, 0);
CMirrors::Mirror.setServiceDownCallback( "*", cbServiceDown, 0);
// CUnifiedNetwork::getInstance()->setServiceDownCallback( "*", cbServiceDown, 0);
CConfigFile::CVar *clientCreature=IService::getInstance()->ConfigFile.getVarPtr ("CreatureDebug");
if (clientCreature)
{
CAIS::instance().setClientCreatureDebug(clientCreature->asInt()!=0);
}
}
///release
void CAIService::release()
{
}
void CAIService::tickRelease (void)
{
CWorldContainer::clear();
// release sub systems
CAIS::instance().release();
CAIDSInterface::release();
CVisualPropertiesInterface::release();
CCombatInterface::release();
CTimeInterface::release();
CEGSInterface::release();
CAISActions::release();
AISHEETS::CSheets::getInstance()->release();
CMessages::release();
CMirrors::release();
CFamilyProfileFactory::instance().release();
CSingletonRegistry::getInstance()->release();
}
void dispatchEvents()
{
H_AUTO(dispatchEvents);
while (!CCombatInterface::_events.empty())
{
CAIEntityPhysical *target=CAIS::instance().getEntityPhysical(CCombatInterface::_events.front()._targetRow);
if (target)
target->processEvent( CCombatInterface::_events.front() );
CCombatInterface::_events.pop_front();
}
}
/*-----------------------------------------------------------------*\
SERVICE UPDATES
\*-----------------------------------------------------------------*/
///update called on each 'tick' message from tick service
void cbTick()
{
// cleanup stat variables
// StatCSpawnBotFauna = 0;
// StatCSpawnBotNpc = 0;
// StatCBotPet = 0;
// StatCAIContinent = 0;
// StatCSpawnGroupFauna = 0;
// StatCSpawnGroupNpc = 0;
// StatCSpawnGroupPet = 0;
// StatCAIInstance = 0;
// StatCMgrFauna = 0;
// StatCMgrNpc = 0;
// StatCMgrPet = 0;
// StatCBotPlayer = 0;
// StatCPlayerManager = 0;
// StatCcontinent = 0;
// StatCRegion = 0;
// StatCCellZone = 0;
if ( CMirrors::mirrorIsReady() )
{
CAIS::instance().update();
CEGSInterface::update();
CTimeInterface::update();
CVisualPropertiesInterface::update();
dispatchEvents();
CMirrors::update();
}
{
H_AUTO(CSingletonRegistry_tickUpdate)
CSingletonRegistry::getInstance()->tickUpdate();
}
}
//prototype for a global routine in commands.cpp
void UpdateWatches();
uint ForceTicks=0;
///update called every coplete cycle of service loop
bool CAIService::update (void)
{
// NLMEMORY::CheckHeap(true);
UpdateWatches();
// NLMEMORY::CheckHeap(true);
if (ForceTicks)
{
// We update a false perception (as if we force ticks, it meens we don't receive true one because we're off-line).
// We make a false tick.
ForceTicks--;
cbTick();
}
CSingletonRegistry::getInstance()->serviceUpdate();
return true;
}
/*-----------------------------------------------------------------*\
NLNET_SERVICE_MAIN
\*-----------------------------------------------------------------*/
NLNET_SERVICE_MAIN (CAIService, "AIS", "ai_service", 0, EmptyCallbackArray, "", "")