- numerous bugfixes including fixing a slowdown introduced in a previous recent checkin.

- Added Network Text Message queue as this is required in some tricky cases
- added more logging of memory cleanup events
- added memory safe snprintf calls
This commit is contained in:
Mark Vejvoda 2011-01-11 22:09:46 +00:00
parent 227f39ccf9
commit ccbd707ae1
13 changed files with 186 additions and 109 deletions

View File

@ -3,13 +3,13 @@
// //
// Copyright (C) 2001-2008 Martiño Figueroa // Copyright (C) 2001-2008 Martiño Figueroa
// //
// You can redistribute this code and/or modify it under // You can redistribute this code and/or modify it under
// the terms of the GNU General Public License as published // the terms of the GNU General Public License as published
// by the Free Software Foundation; either version 2 of the // by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version // License, or (at your option) any later version
// ============================================================== // ==============================================================
#include "ai.h" #include "ai.h"
#include "ai_interface.h" #include "ai_interface.h"
#include "ai_rule.h" #include "ai_rule.h"
#include "unit_type.h" #include "unit_type.h"
@ -85,7 +85,7 @@ string BuildTask::toString() const{
} }
return str; return str;
} }
// ===================================================== // =====================================================
// class UpgradeTask // class UpgradeTask
// ===================================================== // =====================================================
@ -108,7 +108,7 @@ string UpgradeTask::toString() const{
// ===================================================== // =====================================================
void Ai::init(AiInterface *aiInterface, int useStartLocation) { void Ai::init(AiInterface *aiInterface, int useStartLocation) {
this->aiInterface= aiInterface; this->aiInterface= aiInterface;
if(useStartLocation == -1) { if(useStartLocation == -1) {
startLoc = random.randRange(0, aiInterface->getMapMaxPlayers()-1); startLoc = random.randRange(0, aiInterface->getMapMaxPlayers()-1);
} }
@ -136,8 +136,16 @@ void Ai::init(AiInterface *aiInterface, int useStartLocation) {
} }
Ai::~Ai() { Ai::~Ai() {
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] deleting AI aiInterface [%p]\n",__FILE__,__FUNCTION__,__LINE__,aiInterface);
deleteValues(tasks.begin(), tasks.end()); deleteValues(tasks.begin(), tasks.end());
tasks.clear();
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] deleting AI aiInterface [%p]\n",__FILE__,__FUNCTION__,__LINE__,aiInterface);
deleteValues(aiRules.begin(), aiRules.end()); deleteValues(aiRules.begin(), aiRules.end());
aiRules.clear();
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] deleting AI aiInterface [%p]\n",__FILE__,__FUNCTION__,__LINE__,aiInterface);
aiInterface = NULL;
} }
void Ai::update() { void Ai::update() {
@ -176,7 +184,7 @@ void Ai::update() {
} }
// ==================== state requests ==================== // ==================== state requests ====================
int Ai::getCountOfType(const UnitType *ut){ int Ai::getCountOfType(const UnitType *ut){
int count= 0; int count= 0;
@ -235,8 +243,8 @@ const ResourceType *Ai::getNeededResource(int unitIndex) {
return neededResource; return neededResource;
} }
bool Ai::beingAttacked(Vec2i &pos, Field &field, int radius){ bool Ai::beingAttacked(Vec2i &pos, Field &field, int radius){
int count= aiInterface->onSightUnitCount(); int count= aiInterface->onSightUnitCount();
const Unit *unit; const Unit *unit;
for(int i=0; i<count; ++i){ for(int i=0; i<count; ++i){
@ -246,7 +254,7 @@ bool Ai::beingAttacked(Vec2i &pos, Field &field, int radius){
field= unit->getCurrField(); field= unit->getCurrField();
if(pos.dist(aiInterface->getHomeLocation())<radius){ if(pos.dist(aiInterface->getHomeLocation())<radius){
aiInterface->printLog(2, "Being attacked at pos "+intToStr(pos.x)+","+intToStr(pos.y)+"\n"); aiInterface->printLog(2, "Being attacked at pos "+intToStr(pos.x)+","+intToStr(pos.y)+"\n");
return true; return true;
} }
} }
} }
@ -257,11 +265,11 @@ bool Ai::isStableBase(){
if(getCountOfClass(ucWarrior)>minWarriors){ if(getCountOfClass(ucWarrior)>minWarriors){
aiInterface->printLog(4, "Base is stable\n"); aiInterface->printLog(4, "Base is stable\n");
return true; return true;
} }
else{ else{
aiInterface->printLog(4, "Base is not stable\n"); aiInterface->printLog(4, "Base is not stable\n");
return false; return false;
} }
} }
@ -270,12 +278,12 @@ bool Ai::findAbleUnit(int *unitIndex, CommandClass ability, bool idleOnly){
*unitIndex= -1; *unitIndex= -1;
for(int i=0; i<aiInterface->getMyUnitCount(); ++i){ for(int i=0; i<aiInterface->getMyUnitCount(); ++i){
const Unit *unit= aiInterface->getMyUnit(i); const Unit *unit= aiInterface->getMyUnit(i);
if(unit->getType()->hasCommandClass(ability)){ if(unit->getType()->hasCommandClass(ability)){
if(!idleOnly || !unit->anyCommand() || unit->getCurrCommand()->getCommandType()->getClass()==ccStop){ if(!idleOnly || !unit->anyCommand() || unit->getCurrCommand()->getCommandType()->getClass()==ccStop){
units.push_back(i); units.push_back(i);
} }
} }
} }
if(units.empty()){ if(units.empty()){
@ -292,12 +300,12 @@ bool Ai::findAbleUnit(int *unitIndex, CommandClass ability, CommandClass current
*unitIndex= -1; *unitIndex= -1;
for(int i=0; i<aiInterface->getMyUnitCount(); ++i){ for(int i=0; i<aiInterface->getMyUnitCount(); ++i){
const Unit *unit= aiInterface->getMyUnit(i); const Unit *unit= aiInterface->getMyUnit(i);
if(unit->getType()->hasCommandClass(ability)){ if(unit->getType()->hasCommandClass(ability)){
if(unit->anyCommand() && unit->getCurrCommand()->getCommandType()->getClass()==currentCommand){ if(unit->anyCommand() && unit->getCurrCommand()->getCommandType()->getClass()==currentCommand){
units.push_back(i); units.push_back(i);
} }
} }
} }
if(units.empty()){ if(units.empty()){
@ -310,7 +318,7 @@ bool Ai::findAbleUnit(int *unitIndex, CommandClass ability, CommandClass current
} }
bool Ai::findPosForBuilding(const UnitType* building, const Vec2i &searchPos, Vec2i &outPos){ bool Ai::findPosForBuilding(const UnitType* building, const Vec2i &searchPos, Vec2i &outPos){
const int spacing= 1; const int spacing= 1;
for(int currRadius=0; currRadius<maxBuildRadius; ++currRadius){ for(int currRadius=0; currRadius<maxBuildRadius; ++currRadius){
@ -329,7 +337,7 @@ bool Ai::findPosForBuilding(const UnitType* building, const Vec2i &searchPos, Ve
} }
// ==================== tasks ==================== // ==================== tasks ====================
void Ai::addTask(const Task *task){ void Ai::addTask(const Task *task){
tasks.push_back(task); tasks.push_back(task);
@ -367,7 +375,7 @@ void Ai::retryTask(const Task *task){
tasks.remove(task); tasks.remove(task);
tasks.push_back(task); tasks.push_back(task);
} }
// ==================== expansions ==================== // ==================== expansions ====================
void Ai::addExpansion(const Vec2i &pos){ void Ai::addExpansion(const Vec2i &pos){
@ -388,15 +396,15 @@ void Ai::addExpansion(const Vec2i &pos){
} }
Vec2i Ai::getRandomHomePosition(){ Vec2i Ai::getRandomHomePosition(){
if(expansionPositions.empty() || random.randRange(0, 1) == 0){ if(expansionPositions.empty() || random.randRange(0, 1) == 0){
return aiInterface->getHomeLocation(); return aiInterface->getHomeLocation();
} }
return expansionPositions[random.randRange(0, expansionPositions.size()-1)]; return expansionPositions[random.randRange(0, expansionPositions.size()-1)];
} }
// ==================== actions ==================== // ==================== actions ====================
void Ai::sendScoutPatrol(){ void Ai::sendScoutPatrol(){
Vec2i pos; Vec2i pos;
@ -410,7 +418,7 @@ void Ai::sendScoutPatrol(){
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
aiInterface->giveCommand(unit, ccAttack, pos); aiInterface->giveCommand(unit, ccAttack, pos);
aiInterface->printLog(2, "Scout patrol sent to: " + intToStr(pos.x)+","+intToStr(pos.y)+"\n"); aiInterface->printLog(2, "Scout patrol sent to: " + intToStr(pos.x)+","+intToStr(pos.y)+"\n");
} }
} }
@ -429,15 +437,15 @@ void Ai::massiveAttack(const Vec2i &pos, Field field, bool ultraAttack){
if(act != NULL && unit->getType()->hasCommandClass(ccProduce)) { if(act != NULL && unit->getType()->hasCommandClass(ccProduce)) {
producerWarriorCount++; producerWarriorCount++;
} }
if( aiInterface->getControlType() == ctCpuMega || if( aiInterface->getControlType() == ctCpuMega ||
aiInterface->getControlType() == ctNetworkCpuMega) { aiInterface->getControlType() == ctNetworkCpuMega) {
if(producerWarriorCount > maxProducerWarriors) { if(producerWarriorCount > maxProducerWarriors) {
if( if(
unit->getCommandSize()>0 && unit->getCommandSize()>0 &&
unit->getCurrCommand()->getCommandType()!=NULL && ( unit->getCurrCommand()->getCommandType()!=NULL && (
unit->getCurrCommand()->getCommandType()->getClass()==ccBuild || unit->getCurrCommand()->getCommandType()->getClass()==ccBuild ||
unit->getCurrCommand()->getCommandType()->getClass()==ccMorph || unit->getCurrCommand()->getCommandType()->getClass()==ccMorph ||
unit->getCurrCommand()->getCommandType()->getClass()==ccProduce unit->getCurrCommand()->getCommandType()->getClass()==ccProduce
) )
) { ) {
@ -455,7 +463,7 @@ void Ai::massiveAttack(const Vec2i &pos, Field field, bool ultraAttack){
else { else {
isWarrior= !unit->getType()->hasCommandClass(ccHarvest) && !unit->getType()->hasCommandClass(ccProduce); isWarrior= !unit->getType()->hasCommandClass(ccHarvest) && !unit->getType()->hasCommandClass(ccProduce);
} }
bool alreadyAttacking= (unit->getCurrSkill()->getClass() == scAttack); bool alreadyAttacking= (unit->getCurrSkill()->getClass() == scAttack);
if(!alreadyAttacking && act!=NULL && (ultraAttack || isWarrior)) { if(!alreadyAttacking && act!=NULL && (ultraAttack || isWarrior)) {
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
@ -489,7 +497,7 @@ void Ai::returnBase(int unitIndex) {
fi= aiInterface->getFactionIndex(); fi= aiInterface->getFactionIndex();
pos= Vec2i( pos= Vec2i(
random.randRange(-villageRadius, villageRadius), random.randRange(-villageRadius, villageRadius)) + random.randRange(-villageRadius, villageRadius), random.randRange(-villageRadius, villageRadius)) +
getRandomHomePosition(); getRandomHomePosition();
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
@ -505,7 +513,7 @@ void Ai::harvest(int unitIndex) {
Vec2i resPos; Vec2i resPos;
if(hct != NULL && aiInterface->getNearestSightedResource(rt, aiInterface->getHomeLocation(), resPos, false)) { if(hct != NULL && aiInterface->getNearestSightedResource(rt, aiInterface->getHomeLocation(), resPos, false)) {
resPos= resPos+Vec2i(random.randRange(-2, 2), random.randRange(-2, 2)); resPos= resPos+Vec2i(random.randRange(-2, 2), random.randRange(-2, 2));
aiInterface->giveCommand(unitIndex, hct, resPos); aiInterface->giveCommand(unitIndex, hct, resPos);
//aiInterface->printLog(4, "Order harvest pos:" + intToStr(resPos.x)+", "+intToStr(resPos.y)+": "+rrToStr(r)+"\n"); //aiInterface->printLog(4, "Order harvest pos:" + intToStr(resPos.x)+", "+intToStr(resPos.y)+": "+rrToStr(r)+"\n");
} }

View File

@ -62,6 +62,10 @@ AiInterface::AiInterface(Game &game, int factionIndex, int teamIndex, int useSta
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
} }
AiInterface::~AiInterface() {
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] deleting AI factionIndex = %d, teamIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,this->factionIndex,this->teamIndex);
cacheUnitHarvestResourceLookup.clear();
}
// ==================== main ==================== // ==================== main ====================
void AiInterface::update() { void AiInterface::update() {

View File

@ -3,9 +3,9 @@
// //
// Copyright (C) 2001-2008 Martio Figueroa // Copyright (C) 2001-2008 Martio Figueroa
// //
// You can redistribute this code and/or modify it under // You can redistribute this code and/or modify it under
// the terms of the GNU General Public License as published // the terms of the GNU General Public License as published
// by the Free Software Foundation; either version 2 of the // by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version // License, or (at your option) any later version
// ============================================================== // ==============================================================
@ -26,7 +26,7 @@ using Shared::Util::intToStr;
namespace Glest{ namespace Game{ namespace Glest{ namespace Game{
// ===================================================== // =====================================================
// class AiInterface // class AiInterface
// //
/// The AI will interact with the game through this interface /// The AI will interact with the game through this interface
// ===================================================== // =====================================================
@ -50,7 +50,8 @@ private:
std::map<const ResourceType *,int> cacheUnitHarvestResourceLookup; std::map<const ResourceType *,int> cacheUnitHarvestResourceLookup;
public: public:
AiInterface(Game &game, int factionIndex, int teamIndex, int useStartLocation=-1); AiInterface(Game &game, int factionIndex, int teamIndex, int useStartLocation=-1);
~AiInterface();
//main //main
void update(); void update();
@ -61,14 +62,14 @@ public:
//misc //misc
void printLog(int logLevel, const string &s); void printLog(int logLevel, const string &s);
//interact //interact
CommandResult giveCommand(int unitIndex, CommandClass commandClass, const Vec2i &pos=Vec2i(0)); CommandResult giveCommand(int unitIndex, CommandClass commandClass, const Vec2i &pos=Vec2i(0));
CommandResult giveCommand(int unitIndex, const CommandType *commandType, const Vec2i &pos, const UnitType* unitType); CommandResult giveCommand(int unitIndex, const CommandType *commandType, const Vec2i &pos, const UnitType* unitType);
CommandResult giveCommand(int unitIndex, const CommandType *commandType, const Vec2i &pos); CommandResult giveCommand(int unitIndex, const CommandType *commandType, const Vec2i &pos);
CommandResult giveCommand(int unitIndex, const CommandType *commandType, Unit *u= NULL); CommandResult giveCommand(int unitIndex, const CommandType *commandType, Unit *u= NULL);
CommandResult giveCommand(Unit *unit, const CommandType *commandType, const Vec2i &pos); CommandResult giveCommand(Unit *unit, const CommandType *commandType, const Vec2i &pos);
//get data //get data
const ControlType getControlType(); const ControlType getControlType();
int getMapMaxPlayers(); int getMapMaxPlayers();
@ -83,13 +84,13 @@ public:
const Unit *getOnSightUnit(int unitIndex); const Unit *getOnSightUnit(int unitIndex);
const FactionType *getMyFactionType(); const FactionType *getMyFactionType();
Faction *getMyFaction(); Faction *getMyFaction();
const TechTree *getTechTree(); const TechTree *getTechTree();
bool isResourceNear(const Vec2i &pos, const ResourceType *rt, Vec2i &resourcePos, Faction *faction, bool fallbackToPeersHarvestingSameResource) const; bool isResourceNear(const Vec2i &pos, const ResourceType *rt, Vec2i &resourcePos, Faction *faction, bool fallbackToPeersHarvestingSameResource) const;
bool getNearestSightedResource(const ResourceType *rt, const Vec2i &pos, Vec2i &resultPos, bool usableResourceTypeOnly); bool getNearestSightedResource(const ResourceType *rt, const Vec2i &pos, Vec2i &resultPos, bool usableResourceTypeOnly);
bool isAlly(const Unit *unit) const; bool isAlly(const Unit *unit) const;
bool isAlly(int factionIndex) const; bool isAlly(int factionIndex) const;
bool reqsOk(const RequirableType *rt); bool reqsOk(const RequirableType *rt);
bool reqsOk(const CommandType *ct); bool reqsOk(const CommandType *ct);
bool checkCosts(const ProducibleType *pt); bool checkCosts(const ProducibleType *pt);
bool isFreeCells(const Vec2i &pos, int size, Field field); bool isFreeCells(const Vec2i &pos, int size, Field field);

View File

@ -35,14 +35,15 @@ const int Logger::logLineCount= 15;
// ===================== PUBLIC ======================== // ===================== PUBLIC ========================
Logger::Logger(){ Logger::Logger() {
string logs_path = getGameReadWritePath(GameConstants::path_logs_CacheLookupKey); string logs_path = getGameReadWritePath(GameConstants::path_logs_CacheLookupKey);
fileName= logs_path + "log.txt"; fileName= logs_path + "log.txt";
loadingTexture=NULL; loadingTexture=NULL;
showProgressBar = false;
} }
Logger::~Logger(){ Logger::~Logger() {
cleanupLoadingTexture(); cleanupLoadingTexture();
} }
@ -66,12 +67,12 @@ void Logger::cleanupLoadingTexture() {
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
} }
Logger & Logger::getInstance(){ Logger & Logger::getInstance() {
static Logger logger; static Logger logger;
return logger; return logger;
} }
void Logger::add(const string &str, bool renderScreen){ void Logger::add(const string &str, bool renderScreen) {
FILE *f=fopen(fileName.c_str(), "at+"); FILE *f=fopen(fileName.c_str(), "at+");
if(f!=NULL){ if(f!=NULL){
fprintf(f, "%s\n", str.c_str()); fprintf(f, "%s\n", str.c_str());
@ -83,7 +84,7 @@ void Logger::add(const string &str, bool renderScreen){
} }
} }
void Logger::clear(){ void Logger::clear() {
string s="Log file\n"; string s="Log file\n";
FILE *f= fopen(fileName.c_str(), "wt+"); FILE *f= fopen(fileName.c_str(), "wt+");
@ -97,8 +98,7 @@ void Logger::clear(){
fclose(f); fclose(f);
} }
void Logger::loadLoadingScreen(string filepath) {
void Logger::loadLoadingScreen(string filepath){
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
@ -152,13 +152,14 @@ void Logger::renderLoadingScreen() {
metrics.getVirtualW()/4, metrics.getVirtualW()/4,
62*metrics.getVirtualH()/100, false); 62*metrics.getVirtualH()/100, false);
renderer.renderProgressBar( if(showProgressBar == true) {
progress, renderer.renderProgressBar(
metrics.getVirtualW()/4, progress,
59*metrics.getVirtualH()/100, metrics.getVirtualW()/4,
coreData.getDisplayFontSmall(), 59*metrics.getVirtualH()/100,
350,""); // no string here, because it has to be language specific and does not give much information coreData.getDisplayFontSmall(),
350,""); // no string here, because it has to be language specific and does not give much information
}
renderer.swapBuffers(); renderer.swapBuffers();
} }

View File

@ -43,7 +43,8 @@ private:
string subtitle; string subtitle;
string current; string current;
Texture2D *loadingTexture; Texture2D *loadingTexture;
int progress; int progress;
bool showProgressBar;
private: private:
Logger(); Logger();
@ -58,7 +59,9 @@ public:
void setState(const string &state) {this->state= state;} void setState(const string &state) {this->state= state;}
void setSubtitle(const string &subtitle) {this->subtitle= subtitle;} void setSubtitle(const string &subtitle) {this->subtitle= subtitle;}
void setProgress(int value) { this->progress = value; } void setProgress(int value) { this->progress = value; }
int getProgress() const {return progress;} int getProgress() const {return progress;}
void showProgress() { showProgressBar = true;}
void hideProgress() { showProgressBar = false;}
void add(const string &str, bool renderScreen= false); void add(const string &str, bool renderScreen= false);
void loadLoadingScreen(string filepath); void loadLoadingScreen(string filepath);

View File

@ -152,18 +152,18 @@ void CommanderNetworkThread::execute() {
// ===================================================== // =====================================================
Commander::Commander() { Commander::Commander() {
this->networkThread = new CommanderNetworkThread(this); //this->networkThread = new CommanderNetworkThread(this);
this->networkThread->setUniqueID(__FILE__); //this->networkThread->setUniqueID(__FILE__);
this->networkThread->start(); //this->networkThread->start();
} }
Commander::~Commander() { Commander::~Commander() {
if(BaseThread::shutdownAndWait(networkThread) == true) { //if(BaseThread::shutdownAndWait(networkThread) == true) {
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); // SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
delete networkThread; // delete networkThread;
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); // SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
} //}
networkThread = NULL; //networkThread = NULL;
} }
void Commander::init(World *world){ void Commander::init(World *world){
@ -455,6 +455,9 @@ CommandResult Commander::pushNetworkCommand(const NetworkCommand* networkCommand
} }
void Commander::signalNetworkUpdate(Game *game) { void Commander::signalNetworkUpdate(Game *game) {
updateNetwork(game);
/*
if(this->networkThread != NULL) { if(this->networkThread != NULL) {
this->game = game; this->game = game;
this->networkThread->signalUpdate(1); this->networkThread->signalUpdate(1);
@ -465,10 +468,11 @@ void Commander::signalNetworkUpdate(Game *game) {
game->render(); game->render();
} }
} }
*/
} }
void Commander::commanderNetworkUpdateTask(int id) { void Commander::commanderNetworkUpdateTask(int id) {
updateNetwork(game); //updateNetwork(game);
} }
void Commander::updateNetwork(Game *game) { void Commander::updateNetwork(Game *game) {
@ -476,26 +480,28 @@ void Commander::updateNetwork(Game *game) {
//check that this is a keyframe //check that this is a keyframe
//GameSettings *gameSettings = this->world->getGame()->getGameSettings(); //GameSettings *gameSettings = this->world->getGame()->getGameSettings();
GameSettings *gameSettings = game->getGameSettings(); if(game != NULL) {
if( networkManager.isNetworkGame() == false || GameSettings *gameSettings = game->getGameSettings();
(world->getFrameCount() % gameSettings->getNetworkFramePeriod()) == 0) { if( networkManager.isNetworkGame() == false ||
(world->getFrameCount() % gameSettings->getNetworkFramePeriod()) == 0) {
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] networkManager.isNetworkGame() = %d,world->getFrameCount() = %d, gameSettings->getNetworkFramePeriod() = %d\n",__FILE__,__FUNCTION__,__LINE__,networkManager.isNetworkGame(),world->getFrameCount(),gameSettings->getNetworkFramePeriod()); SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] networkManager.isNetworkGame() = %d,world->getFrameCount() = %d, gameSettings->getNetworkFramePeriod() = %d\n",__FILE__,__FUNCTION__,__LINE__,networkManager.isNetworkGame(),world->getFrameCount(),gameSettings->getNetworkFramePeriod());
GameNetworkInterface *gameNetworkInterface= NetworkManager::getInstance().getGameNetworkInterface(); GameNetworkInterface *gameNetworkInterface= NetworkManager::getInstance().getGameNetworkInterface();
perfTimer.start(); perfTimer.start();
//update the keyframe //update the keyframe
gameNetworkInterface->updateKeyframe(world->getFrameCount()); gameNetworkInterface->updateKeyframe(world->getFrameCount());
if(perfTimer.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] gameNetworkInterface->updateKeyframe for %d took %lld msecs\n",__FILE__,__FUNCTION__,__LINE__,world->getFrameCount(),perfTimer.getMillis()); if(perfTimer.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] gameNetworkInterface->updateKeyframe for %d took %lld msecs\n",__FILE__,__FUNCTION__,__LINE__,world->getFrameCount(),perfTimer.getMillis());
perfTimer.start(); perfTimer.start();
//give pending commands //give pending commands
for(int i= 0; i < gameNetworkInterface->getPendingCommandCount(); ++i){ for(int i= 0; i < gameNetworkInterface->getPendingCommandCount(); ++i){
giveNetworkCommand(gameNetworkInterface->getPendingCommand(i)); giveNetworkCommand(gameNetworkInterface->getPendingCommand(i));
} }
if(perfTimer.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] giveNetworkCommand took %lld msecs, PendingCommandCount = %d\n",__FILE__,__FUNCTION__,__LINE__,perfTimer.getMillis(),gameNetworkInterface->getPendingCommandCount()); if(perfTimer.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] giveNetworkCommand took %lld msecs, PendingCommandCount = %d\n",__FILE__,__FUNCTION__,__LINE__,perfTimer.getMillis(),gameNetworkInterface->getPendingCommandCount());
gameNetworkInterface->clearPendingCommands(); gameNetworkInterface->clearPendingCommands();
}
} }
} }

View File

@ -77,8 +77,8 @@ private:
World *world; World *world;
Chrono perfTimer; Chrono perfTimer;
CommanderNetworkThread *networkThread; //CommanderNetworkThread *networkThread;
Game *game; //Game *game;
public: public:
Commander(); Commander();

View File

@ -89,6 +89,9 @@ Game::Game(Program *program, const GameSettings *gameSettings):
speed= sNormal; speed= sNormal;
showFullConsole= false; showFullConsole= false;
Logger &logger= Logger::getInstance();
logger.showProgress();
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
} }
@ -108,14 +111,16 @@ Game::~Game() {
logger.loadLoadingScreen(""); logger.loadLoadingScreen("");
logger.setState(Lang::getInstance().get("Deleting")); logger.setState(Lang::getInstance().get("Deleting"));
logger.add("Game", true); logger.add("Game", true);
logger.hideProgress();
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
SoundRenderer::getInstance().stopAllSounds(); SoundRenderer::getInstance().stopAllSounds();
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
deleteValues(aiInterfaces.begin(), aiInterfaces.end()); deleteValues(aiInterfaces.begin(), aiInterfaces.end());
aiInterfaces.clear();
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
@ -125,7 +130,7 @@ Game::~Game() {
world.end(); //must die before selection because of referencers world.end(); //must die before selection because of referencers
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] aiInterfaces.size() = %d\n",__FILE__,__FUNCTION__,__LINE__,aiInterfaces.size());
// MUST DO THIS LAST!!!! Because objects above have pointers to things like // MUST DO THIS LAST!!!! Because objects above have pointers to things like
// unit particles and fade them out etc and this end method deletes the original // unit particles and fade them out etc and this end method deletes the original
@ -546,6 +551,8 @@ void Game::init(bool initForPreviewOnly)
bool isNetworkGame = this->gameSettings.isNetworkGame(); bool isNetworkGame = this->gameSettings.isNetworkGame();
NetworkRole role = networkManager.getNetworkRole(); NetworkRole role = networkManager.getNetworkRole();
deleteValues(aiInterfaces.begin(), aiInterfaces.end());
aiInterfaces.resize(world.getFactionCount()); aiInterfaces.resize(world.getFactionCount());
for(int i=0; i < world.getFactionCount(); ++i) { for(int i=0; i < world.getFactionCount(); ++i) {
Faction *faction= world.getFaction(i); Faction *faction= world.getFaction(i);

View File

@ -124,13 +124,17 @@ void ClientInterface::update() {
} }
} }
int lastSendElapsed = difftime(time(NULL),lastNetworkCommandListSendTime); double lastSendElapsed = difftime(time(NULL),lastNetworkCommandListSendTime);
if(lastNetworkCommandListSendTime > 0) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] lastSendElapsed = %d\n",__FILE__,__FUNCTION__,__LINE__,lastSendElapsed); if(lastNetworkCommandListSendTime > 0) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] lastSendElapsed = %f\n",__FILE__,__FUNCTION__,__LINE__,lastSendElapsed);
if(networkMessageCommandList.getCommandCount() > 0 || if(networkMessageCommandList.getCommandCount() > 0 ||
(lastNetworkCommandListSendTime > 0 && lastSendElapsed >= ClientInterface::maxNetworkCommandListSendTimeWait)) { (lastNetworkCommandListSendTime > 0 && lastSendElapsed >= ClientInterface::maxNetworkCommandListSendTimeWait)) {
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
lastNetworkCommandListSendTime = time(NULL); lastNetworkCommandListSendTime = time(NULL);
sendMessage(&networkMessageCommandList); sendMessage(&networkMessageCommandList);
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
} }
// Possible cause of out of synch since we have more commands that need // Possible cause of out of synch since we have more commands that need

View File

@ -263,6 +263,10 @@ ConnectionSlot::ConnectionSlot(ServerInterface* serverInterface, int playerIndex
ConnectionSlot::~ConnectionSlot() { ConnectionSlot::~ConnectionSlot() {
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] START\n",__FILE__,__FUNCTION__,__LINE__); SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] START\n",__FILE__,__FUNCTION__,__LINE__);
close();
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
if(BaseThread::shutdownAndWait(slotThreadWorker) == true) { if(BaseThread::shutdownAndWait(slotThreadWorker) == true) {
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
delete slotThreadWorker; delete slotThreadWorker;
@ -270,8 +274,6 @@ ConnectionSlot::~ConnectionSlot() {
} }
slotThreadWorker = NULL; slotThreadWorker = NULL;
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
close();
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] END\n",__FILE__,__FUNCTION__); SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] END\n",__FILE__,__FUNCTION__);
} }

View File

@ -264,22 +264,23 @@ bool ServerInterface::switchSlot(int fromPlayerIndex,int toPlayerIndex) {
} }
void ServerInterface::removeSlot(int playerIndex,int lockedSlotIndex) { void ServerInterface::removeSlot(int playerIndex,int lockedSlotIndex) {
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d playerIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,playerIndex); SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] playerIndex = %d, lockedSlotIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,playerIndex,lockedSlotIndex);
MutexSafeWrapper safeMutex(&serverSynchAccessor,intToStr(__LINE__)); MutexSafeWrapper safeMutex(&serverSynchAccessor,intToStr(__LINE__));
// Mention to everyone that this player is disconnected // Mention to everyone that this player is disconnected
MutexSafeWrapper safeMutexSlot(NULL,intToStr(__LINE__) + "_" + intToStr(playerIndex)); MutexSafeWrapper safeMutexSlot(NULL,intToStr(__LINE__) + "_" + intToStr(playerIndex));
if(playerIndex != lockedSlotIndex) { if(playerIndex != lockedSlotIndex) {
safeMutexSlot.setMutex(&slotAccessorMutexes[playerIndex],intToStr(__LINE__) + "_" + intToStr(playerIndex)); SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] playerIndex = %d, lockedSlotIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,playerIndex,lockedSlotIndex);
safeMutexSlot.setMutex(&slotAccessorMutexes[playerIndex],intToStr(__LINE__) + string("_") + intToStr(playerIndex));
} }
ConnectionSlot *slot = slots[playerIndex]; ConnectionSlot *slot = slots[playerIndex];
bool notifyDisconnect = false; bool notifyDisconnect = false;
char szBuf[4096]=""; char szBuf[4096]="";
if( slot != NULL) { if(slot != NULL) {
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d playerIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,playerIndex); SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] playerIndex = %d, lockedSlotIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,playerIndex,lockedSlotIndex);
if(slot->getLastReceiveCommandListTime() > 0) { if(slot->getLastReceiveCommandListTime() > 0) {
const char* msgTemplate = "Player %s, disconnected from the game."; const char* msgTemplate = "Player %s, disconnected from the game.";
@ -293,30 +294,31 @@ void ServerInterface::removeSlot(int playerIndex,int lockedSlotIndex) {
notifyDisconnect = true; notifyDisconnect = true;
} }
} }
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d playerIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,playerIndex); SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] playerIndex = %d, lockedSlotIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,playerIndex,lockedSlotIndex);
slots[playerIndex]= NULL; slots[playerIndex]= NULL;
safeMutexSlot.ReleaseLock(); safeMutexSlot.ReleaseLock();
safeMutex.ReleaseLock(); safeMutex.ReleaseLock();
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d playerIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,playerIndex); SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] playerIndex = %d, lockedSlotIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,playerIndex,lockedSlotIndex);
delete slot; delete slot;
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d playerIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,playerIndex); SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] playerIndex = %d, lockedSlotIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,playerIndex,lockedSlotIndex);
updateListen(); updateListen();
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d playerIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,playerIndex); SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] playerIndex = %d, lockedSlotIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,playerIndex,lockedSlotIndex);
if(notifyDisconnect == true) { if(notifyDisconnect == true) {
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d playerIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,playerIndex); SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] playerIndex = %d, lockedSlotIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,playerIndex,lockedSlotIndex);
string sMsg = szBuf; string sMsg = szBuf;
sendTextMessage(sMsg,-1, true, lockedSlotIndex); //sendTextMessage(sMsg,-1, true, lockedSlotIndex);
queueTextMessage(sMsg,-1, true);
} }
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d playerIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,playerIndex); SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] playerIndex = %d, lockedSlotIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,playerIndex,lockedSlotIndex);
} }
ConnectionSlot* ServerInterface::getSlot(int playerIndex) { ConnectionSlot* ServerInterface::getSlot(int playerIndex) {
@ -602,6 +604,8 @@ void ServerInterface::update() {
// properly identified themselves within the alloted time period // properly identified themselves within the alloted time period
validateConnectedClients(); validateConnectedClients();
processTextMessageQueue();
std::map<PLATFORM_SOCKET,bool> socketTriggeredList; std::map<PLATFORM_SOCKET,bool> socketTriggeredList;
//update all slots //update all slots
updateSocketTriggeredList(socketTriggeredList); updateSocketTriggeredList(socketTriggeredList);
@ -642,7 +646,7 @@ void ServerInterface::update() {
threadsDone = true; threadsDone = true;
// Examine all threads for completion of delegation // Examine all threads for completion of delegation
for(int i= 0; exitServer == false && i < GameConstants::maxPlayers; ++i) { for(int i= 0; exitServer == false && i < GameConstants::maxPlayers; ++i) {
MutexSafeWrapper safeMutexSlot(&slotAccessorMutexes[i],intToStr(__LINE__) + "_" + intToStr(i)); MutexSafeWrapper safeMutexSlot(&slotAccessorMutexes[i],intToStr(__LINE__) + string("_") + intToStr(i));
ConnectionSlot* connectionSlot = slots[i]; ConnectionSlot* connectionSlot = slots[i];
if(connectionSlot != NULL && mapSlotSignalledList[i] == true && if(connectionSlot != NULL && mapSlotSignalledList[i] == true &&
slotsCompleted.find(i) == slotsCompleted.end()) { slotsCompleted.find(i) == slotsCompleted.end()) {
@ -1095,6 +1099,27 @@ void ServerInterface::waitUntilReady(Checksum* checksum) {
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s] END\n",__FUNCTION__); SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s] END\n",__FUNCTION__);
} }
void ServerInterface::processTextMessageQueue() {
MutexSafeWrapper safeMutexSlot(&textMessageQueueThreadAccessor,intToStr(__LINE__));
if(textMessageQueue.size() > 0) {
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
for(int i = 0; i < textMessageQueue.size(); ++i) {
TextMessageQueue &item = textMessageQueue[i];
sendTextMessage(item.text, item.teamIndex, item.echoLocal);
}
textMessageQueue.clear();
}
}
void ServerInterface::queueTextMessage(const string &text, int teamIndex, bool echoLocal) {
MutexSafeWrapper safeMutexSlot(&textMessageQueueThreadAccessor,intToStr(__LINE__));
TextMessageQueue item;
item.text = text;
item.teamIndex = teamIndex;
item.echoLocal = echoLocal;
textMessageQueue.push_back(item);
}
void ServerInterface::sendTextMessage(const string &text, int teamIndex, bool echoLocal) { void ServerInterface::sendTextMessage(const string &text, int teamIndex, bool echoLocal) {
sendTextMessage(text, teamIndex, echoLocal, -1); sendTextMessage(text, teamIndex, echoLocal, -1);
} }
@ -1327,6 +1352,8 @@ void ServerInterface::broadcastMessage(const NetworkMessage* networkMessage, int
} }
} }
else { else {
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
for(int i= 0; exitServer == false && i < GameConstants::maxPlayers; ++i) { for(int i= 0; exitServer == false && i < GameConstants::maxPlayers; ++i) {
MutexSafeWrapper safeMutexSlot(NULL,intToStr(__LINE__) + "_" + intToStr(i)); MutexSafeWrapper safeMutexSlot(NULL,intToStr(__LINE__) + "_" + intToStr(i));
if(i != lockedSlotIndex) { if(i != lockedSlotIndex) {

View File

@ -35,6 +35,13 @@ namespace Glest{ namespace Game{
class ServerInterface: public GameNetworkInterface, public ConnectionSlotCallbackInterface, public SimpleTaskCallbackInterface, public FTPClientValidationInterface { class ServerInterface: public GameNetworkInterface, public ConnectionSlotCallbackInterface, public SimpleTaskCallbackInterface, public FTPClientValidationInterface {
class TextMessageQueue {
public:
string text;
int teamIndex;
bool echoLocal;
};
private: private:
ConnectionSlot* slots[GameConstants::maxPlayers]; ConnectionSlot* slots[GameConstants::maxPlayers];
Mutex slotAccessorMutexes[GameConstants::maxPlayers]; Mutex slotAccessorMutexes[GameConstants::maxPlayers];
@ -57,6 +64,9 @@ private:
bool exitServer; bool exitServer;
int64 nextEventId; int64 nextEventId;
Mutex textMessageQueueThreadAccessor;
vector<TextMessageQueue> textMessageQueue;
public: public:
ServerInterface(); ServerInterface();
virtual ~ServerInterface(); virtual ~ServerInterface();
@ -75,6 +85,8 @@ public:
virtual void sendTextMessage(const string &text, int teamIndex, bool echoLocal=false); virtual void sendTextMessage(const string &text, int teamIndex, bool echoLocal=false);
void sendTextMessage(const string &text, int teamIndex, bool echoLocal, int lockedSlotIndex); void sendTextMessage(const string &text, int teamIndex, bool echoLocal, int lockedSlotIndex);
void queueTextMessage(const string &text, int teamIndex, bool echoLocal=false);
virtual void quitGame(bool userManuallyQuit); virtual void quitGame(bool userManuallyQuit);
//misc //misc
@ -138,6 +150,8 @@ private:
std::map<string,string> publishToMasterserver(); std::map<string,string> publishToMasterserver();
int64 getNextEventId(); int64 getNextEventId();
void processTextMessageQueue();
}; };
}}//end namespace }}//end namespace

View File

@ -95,8 +95,8 @@ bool strToFloat(const string &s, float *f){
return true; return true;
} }
string boolToStr(bool b){ string boolToStr(bool b) {
if(b){ if(b) {
return "1"; return "1";
} }
else{ else{
@ -106,25 +106,25 @@ string boolToStr(bool b){
string intToStr(int64 i) { string intToStr(int64 i) {
char str[strSize]=""; char str[strSize]="";
sprintf(str, "%lld", (long long int)i); snprintf(str, strSize-1, "%lld", (long long int)i);
return str; return str;
} }
string intToHex(int i){ string intToHex(int i){
char str[strSize]=""; char str[strSize]="";
sprintf(str, "%x", i); snprintf(str, strSize-1, "%x", i);
return str; return str;
} }
string floatToStr(float f,int precsion){ string floatToStr(float f,int precsion) {
char str[strSize]=""; char str[strSize]="";
sprintf(str, "%.*f", precsion,f); snprintf(str, strSize-1, "%.*f", precsion,f);
return str; return str;
} }
string doubleToStr(double d,int precsion){ string doubleToStr(double d,int precsion) {
char str[strSize]=""; char str[strSize]="";
sprintf(str, "%.*f", precsion,d); snprintf(str, strSize-1, "%.*f", precsion,d);
return str; return str;
} }