<commit_before>#include "./JPetScopeModule.h"

#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <utility>

#include "boost/regex.hpp"
#include "boost/filesystem.hpp"

#include <TSystem.h>
#include <TApplication.h>
#include <TCanvas.h>

#include "../JPetSigCh/JPetSigCh.h"
#include "../JPetRecoSignal/JPetRecoSignal.h"
#include "../JPetPhysSignal/JPetPhysSignal.h"
#include "../JPetManager/JPetManager.h"
#include "../JPetParamBank/JPetParamBank.h"
#include "../JPetTreeHeader/JPetTreeHeader.h"

using namespace std;
using namespace boost::filesystem;

ClassImp(JPetScopeModule);

static multimap <int, string> :: iterator fIt;

JPetScopeModule::JPetScopeModule(): JPetAnalysisModule() {
  gSystem->Load("libTree");
}

JPetScopeModule::JPetScopeModule(const char* name, const char* title): JPetAnalysisModule(name, title) {
  gSystem->Load("libTree");
}

JPetScopeModule::~JPetScopeModule() {
  if (fWriter != 0) {
    delete fWriter;
    fWriter = 0;
  }
}

int JPetScopeModule::readFromConfig (const char* fmt, ...) {

  va_list args;
  va_start (args, fmt);

  string buf;

  getline (fConfigFile, buf);
  while (fConfigFile.good() && buf.size() < 2 ) getline(fConfigFile, buf);
  if (!fConfigFile.good()) {va_end(args); return -1;}

  //buf.erase(0, to_erase);
  int ret = vsscanf(buf.c_str(), fmt, args);

  va_end(args);

  return ret;
}

void JPetScopeModule::createInputObjects(const char* inputFilename)
{
  INFO( Form("Starting %s.", GetName() ) );

  fConfigFile.open(fInFilename);
  if (!fConfigFile.is_open()) {
    ERROR("Cannot open config file. Exiting");
    exit(-1);
  }

  string buf;
  string cfg_dir = path(fInFilename).parent_path().string();
  string data_dir;
  char cbuf[256];
  int a, b, c;
  //int p1, p2, p3, p4, s1, s2, coll;

  // Read configuration data
  for (int i = 0; i<1; ++i){

  if (readFromConfig("%*2c %d %s", &(fConfig.pm1), cbuf) <= 0) break;
  fConfig.file1 = string(cbuf);

  if (readFromConfig("%*2c %d %s", &(fConfig.pm2), cbuf) <= 0) break;
  fConfig.file2 = string(cbuf);

  if (readFromConfig("%*2c %d %s", &(fConfig.pm3), cbuf) <= 0) break;
  fConfig.file3 = string(cbuf);

  if (readFromConfig("%*2c %d %s", &(fConfig.pm4), cbuf) <= 0) break;
  fConfig.file4 = string(cbuf);

  if (readFromConfig("%*5c %d", &(fConfig.scin1)) <= 0) break;

  if (readFromConfig("%*5c %d", &(fConfig.scin2)) <= 0) break;

  if (readFromConfig("%s", cbuf) <= 0) break;
  data_dir = string(cbuf);

  while (true) {
    a = 0;
    b = 0;
    c = 0;
    int d = readFromConfig("%d %d %d", &a, &b, &c);
    if (d <= 0) break;
    else if (d == 1) {
      // Add single position
      fCollPositions.insert(a);
    }
    else {
      if (d == 2) {c = 1;}
      // Add multiple positions
      for (int j = a; j <= b; j += c) {
        fCollPositions.insert(j);
      }
    }
  }

  }

  //Create ParamBank
  JPetPM pm1;
  JPetPM pm2;
  JPetPM pm3;
  JPetPM pm4;
  pm1.setID(fConfig.pm1);
  pm2.setID(fConfig.pm2);
  pm3.setID(fConfig.pm3);
  pm4.setID(fConfig.pm4);

  JPetScin scin1;
  JPetScin scin2;
  scin1.setID(fConfig.scin1);
  scin2.setID(fConfig.scin2);

  fParamBank = new JPetParamBank();
  fParamBank->addPM(pm1);
  fParamBank->addPM(pm2);
  fParamBank->addPM(pm3);
  fParamBank->addPM(pm4);
  fParamBank->addScintillator(scin1);
  fParamBank->addScintillator(scin2);

  fConfig.ppm1   = &(fParamBank->getPM(0));
  fConfig.ppm2   = &(fParamBank->getPM(1));
  fConfig.ppm3   = &(fParamBank->getPM(2));
  fConfig.ppm4   = &(fParamBank->getPM(3));
  fConfig.pscin1 = &(fParamBank->getScintillator(0));
  fConfig.pscin2 = &(fParamBank->getScintillator(1));

  fConfig.ppm1->setScin(*(fConfig.pscin1));
  fConfig.ppm2->setScin(*(fConfig.pscin1));
  fConfig.ppm3->setScin(*(fConfig.pscin2));
  fConfig.ppm4->setScin(*(fConfig.pscin2));

  // Add oscilloscope files
  for (set<int>::iterator it = fCollPositions.begin(); it != fCollPositions.end(); ++it) {
    string starting_loc  = cfg_dir;
           starting_loc += "/";
           starting_loc += data_dir;
	   starting_loc += "/";
	   starting_loc += to_string (*it);

    path current_dir(starting_loc);
    boost::regex pattern(Form("%s_\\d*.txt", fConfig.file1.c_str()));

    if (exists(current_dir))
    for (recursive_directory_iterator iter(current_dir), end; iter != end; ++iter) {
      string name = iter->path().leaf().string();
      string dir;
      if (regex_match(name, pattern)) {
        name[1] = (fConfig.file1)[1];
        dir = iter->path().parent_path().string();
        dir += "/";
        dir += name;
	int tpos = *it;
        fFiles.insert(pair<int, string> (tpos, dir));
      }
    }
    else {
      string msg  = "Directory: \"";
             msg += current_dir.string();
             msg += "\" does not exist.";
      ERROR(msg.c_str());
    }
  }
  fIt = fFiles.begin();
  //printFiles();
  fWriter = 0;
}

void JPetScopeModule::createOutputObjects(const char* outputFilename) {

  if (fFiles.empty()) {
    ERROR("No files for processing.");
  }
  else {
    fCurrentPosition = (*fIt).first;
    terminate();

    INFO (Form("Creating root file for position %d", fCurrentPosition));

    string out_fn(fOutFilename.Data());
    int last_dot = out_fn.find_last_of(".");

    string out_fn2  = out_fn.substr(0,last_dot+1);
           out_fn2 += to_string(fCurrentPosition);
           out_fn2 += out_fn.substr(last_dot);

    fWriter = new JPetWriter(out_fn2.c_str());

    fHeader = new JPetTreeHeader(JPetManager::GetManager().getRunNumber());
    fHeader->setBaseFileName(JPetManager::GetManager().getInputFileName().c_str());
    fHeader->addStageInfo(GetName(), GetTitle(), MODULE_VERSION, JPetManager::GetManager().GetTimeString());
    fHeader->setSourcePosition(fCurrentPosition);

    fWriter->writeHeader(fHeader);
    fWriter->writeObject(fParamBank, "ParamBank");
  }
}

void JPetScopeModule::exec() {

  while (fIt != fFiles.end()) {

    if ((*fIt).first != fCurrentPosition) createOutputObjects();

    JPetPhysSignal psig1, psig2, psig3, psig4;
    JPetHit hit1, hit2;

    string osc_file = (*fIt).second;
    string filename;

    int tslot_index;
    sscanf(path(osc_file).filename().string().c_str(), "%*3s %d", &tslot_index);

    //INFO (Form("Processing file: %s", osc_file.c_str()));
    JPetRecoSignal& rsig1 = fReader.generateSignal(osc_file.c_str());
    rsig1.setPM(*(fConfig.ppm1));
    rsig1.setTSlotIndex(tslot_index);
    psig1.setRecoSignal(rsig1);

    filename = path((*fIt).second).filename().string();
    filename[1] = (fConfig.file2)[1];
    osc_file = path((*fIt).second).parent_path().string();
    osc_file+= "/";
    osc_file+= filename;

    //INFO (Form("Processing file: %s", osc_file.c_str()));
    JPetRecoSignal& rsig2 = fReader.generateSignal(osc_file.c_str());
    rsig2.setPM(*(fConfig.ppm2));
    rsig2.setTSlotIndex(tslot_index);
    psig2.setRecoSignal(rsig2);

    filename = path((*fIt).second).filename().string();
    filename[1] = (fConfig.file3)[1];
    osc_file = path((*fIt).second).parent_path().string();
    osc_file+= "/";
    osc_file+= filename;

    //INFO (Form("Processing file: %s", osc_file.c_str()));
    JPetRecoSignal& rsig3 = fReader.generateSignal(osc_file.c_str());
    rsig3.setPM(*(fConfig.ppm3));
    rsig3.setTSlotIndex(tslot_index);
    psig3.setRecoSignal(rsig3);

    filename = path((*fIt).second).filename().string();
    filename[1] = (fConfig.file4)[1];
    osc_file  = path((*fIt).second).parent_path().string();
    osc_file += "/";
    osc_file += filename;

    //INFO (Form("Processing file: %s", osc_file.c_str()));
    JPetRecoSignal& rsig4 = fReader.generateSignal(osc_file.c_str());
    rsig4.setPM(*(fConfig.ppm4));
    rsig4.setTSlotIndex(tslot_index);
    psig4.setRecoSignal(rsig4);

    hit1.setSignals(psig1, psig2);
    hit1.setScinID(fConfig.scin1);

    hit2.setSignals(psig3, psig4);
    hit2.setScinID(fConfig.scin2);

    JPetLOR event;

    event.setHits(hit1, hit2);

    fWriter->write(event);

    break;
  }
  fIt++;
}

void JPetScopeModule::terminate() {
//  assert(fWriter);
  if(fWriter)
  if(fWriter->isOpen()) {
    //std::cout <<"in JPetScope terminate()" <<std::endl;
    fWriter->closeFile();
    delete fWriter;
    fWriter = 0;
  }
}

void JPetScopeModule::printCollPositions () {
  INFO ("Printing all collimator positions:");
  for (set<int>::iterator iter = fCollPositions.begin(); iter != fCollPositions.end(); ++iter) {
    INFO (Form("collimator position: %d", *iter));
  }
}

void JPetScopeModule::printFiles () {
  INFO ("Printing all files:");
  for (map<int, string>::iterator iter = fFiles.begin(); iter != fFiles.end(); ++iter) {
    INFO (Form("%3d %s", (*iter).first, (*iter).second.c_str()));
  }
}

void JPetScopeModule::setFileName(const char* name)
{
  fInFilename = TString(name);
  fOutFilename = TString(name);
  fOutFilename.ReplaceAll(".cfg", "");
  fOutFilename.Append(".scope.eve.root");
}
<commit_msg>solved problem #632<commit_after>#include "./JPetScopeModule.h"

#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <utility>

#include "boost/regex.hpp"
#include "boost/filesystem.hpp"

#include <TSystem.h>
#include <TApplication.h>
#include <TCanvas.h>

#include "../JPetSigCh/JPetSigCh.h"
#include "../JPetRecoSignal/JPetRecoSignal.h"
#include "../JPetPhysSignal/JPetPhysSignal.h"
#include "../JPetManager/JPetManager.h"
#include "../JPetParamBank/JPetParamBank.h"
#include "../JPetTreeHeader/JPetTreeHeader.h"

using namespace std;
using namespace boost::filesystem;

ClassImp(JPetScopeModule);

static multimap <int, string> :: iterator fIt;

JPetScopeModule::JPetScopeModule(): JPetAnalysisModule() {
  gSystem->Load("libTree");
}

JPetScopeModule::JPetScopeModule(const char* name, const char* title): JPetAnalysisModule(name, title) {
  gSystem->Load("libTree");
}

JPetScopeModule::~JPetScopeModule() {
  if (fWriter != 0) {
    delete fWriter;
    fWriter = 0;
  }
}

int JPetScopeModule::readFromConfig (const char* fmt, ...) {

  va_list args;
  va_start (args, fmt);

  string buf;

  getline (fConfigFile, buf);
  while (fConfigFile.good() && buf.size() < 2 ) getline(fConfigFile, buf);
  if (!fConfigFile.good()) {va_end(args); return -1;}

  //buf.erase(0, to_erase);
  int ret = vsscanf(buf.c_str(), fmt, args);

  va_end(args);

  return ret;
}

void JPetScopeModule::createInputObjects(const char* inputFilename)
{
  INFO( Form("Starting %s.", GetName() ) );

  fConfigFile.open(fInFilename);
  if (!fConfigFile.is_open()) {
    ERROR("Cannot open config file. Exiting");
    exit(-1);
  }

  string buf;
  string cfg_dir = path(fInFilename).parent_path().string();
  string data_dir;
  char cbuf[256];
  int a, b, c;
  //int p1, p2, p3, p4, s1, s2, coll;

  // Read configuration data
  for (int i = 0; i<1; ++i){

  if (readFromConfig("%*2c %d %s", &(fConfig.pm1), cbuf) <= 0) break;
  fConfig.file1 = string(cbuf);

  if (readFromConfig("%*2c %d %s", &(fConfig.pm2), cbuf) <= 0) break;
  fConfig.file2 = string(cbuf);

  if (readFromConfig("%*2c %d %s", &(fConfig.pm3), cbuf) <= 0) break;
  fConfig.file3 = string(cbuf);

  if (readFromConfig("%*2c %d %s", &(fConfig.pm4), cbuf) <= 0) break;
  fConfig.file4 = string(cbuf);

  if (readFromConfig("%*5c %d", &(fConfig.scin1)) <= 0) break;

  if (readFromConfig("%*5c %d", &(fConfig.scin2)) <= 0) break;

  if (readFromConfig("%s", cbuf) <= 0) break;
  data_dir = string(cbuf);

  while (true) {
    a = 0;
    b = 0;
    c = 0;
    int d = readFromConfig("%d %d %d", &a, &b, &c);
    if (d <= 0) break;
    else if (d == 1) {
      // Add single position
      fCollPositions.insert(a);
    }
    else {
      if (d == 2) {c = 1;}
      // Add multiple positions
      for (int j = a; j <= b; j += c) {
        fCollPositions.insert(j);
      }
    }
  }

  }

  //Create ParamBank
  JPetPM pm1;
  JPetPM pm2;
  JPetPM pm3;
  JPetPM pm4;
  pm1.setID(fConfig.pm1);
  pm2.setID(fConfig.pm2);
  pm3.setID(fConfig.pm3);
  pm4.setID(fConfig.pm4);

  JPetScin scin1;
  JPetScin scin2;
  scin1.setID(fConfig.scin1);
  scin2.setID(fConfig.scin2);

  fParamBank = new JPetParamBank();
  fParamBank->addPM(pm1);
  fParamBank->addPM(pm2);
  fParamBank->addPM(pm3);
  fParamBank->addPM(pm4);
  fParamBank->addScintillator(scin1);
  fParamBank->addScintillator(scin2);

  fConfig.ppm1   = &(fParamBank->getPM(0));
  fConfig.ppm2   = &(fParamBank->getPM(1));
  fConfig.ppm3   = &(fParamBank->getPM(2));
  fConfig.ppm4   = &(fParamBank->getPM(3));
  fConfig.pscin1 = &(fParamBank->getScintillator(0));
  fConfig.pscin2 = &(fParamBank->getScintillator(1));

  fConfig.ppm1->setScin(*(fConfig.pscin1));
  fConfig.ppm2->setScin(*(fConfig.pscin1));
  fConfig.ppm3->setScin(*(fConfig.pscin2));
  fConfig.ppm4->setScin(*(fConfig.pscin2));

  // Add oscilloscope files
  for (set<int>::iterator it = fCollPositions.begin(); it != fCollPositions.end(); ++it) {
    string starting_loc  = cfg_dir;
           starting_loc += "/";
           starting_loc += data_dir;
	   starting_loc += "/";
	   starting_loc += to_string (*it);

    path current_dir(starting_loc);
    boost::regex pattern(Form("%s_\\d*.txt", fConfig.file1.c_str()));

    if (exists(current_dir))
    for (recursive_directory_iterator iter(current_dir), end; iter != end; ++iter) {
      string name = iter->path().leaf().string();
      string dir;
      if (regex_match(name, pattern)) {
        name[1] = (fConfig.file1)[1];
        dir = iter->path().parent_path().string();
        dir += "/";
        dir += name;
	int tpos = *it;
        fFiles.insert(pair<int, string> (tpos, dir));
      }
    }
    else {
      string msg  = "Directory: \"";
             msg += current_dir.string();
             msg += "\" does not exist.";
      ERROR(msg.c_str());
    }
  }
  fIt = fFiles.begin();
  //printFiles();
  fWriter = 0;
}

void JPetScopeModule::createOutputObjects(const char* outputFilename) {

  if (fFiles.empty()) {
    ERROR("No files for processing.");
  }
  else {
    fCurrentPosition = (*fIt).first;
    terminate();

    INFO (Form("Creating root file for position %d", fCurrentPosition));

    string out_fn(fOutFilename.Data());
    int last_dot = out_fn.find_last_of(".");

    string out_fn2  = out_fn.substr(0,last_dot+1);
           out_fn2 += to_string(fCurrentPosition);
           out_fn2 += out_fn.substr(last_dot);

    fWriter = new JPetWriter(out_fn2.c_str());

    fHeader = new JPetTreeHeader(JPetManager::GetManager().getRunNumber());
    fHeader->setBaseFileName(JPetManager::GetManager().getInputFileName().c_str());
    fHeader->addStageInfo(GetName(), GetTitle(), MODULE_VERSION, JPetManager::GetManager().GetTimeString());
    fHeader->setSourcePosition(fCurrentPosition);

    fWriter->writeHeader(fHeader);
  }
}

void JPetScopeModule::exec() {

  while (fIt != fFiles.end()) {

    if ((*fIt).first != fCurrentPosition) createOutputObjects();
    fWriter->writeObject(fParamBank, "ParamBank");

    JPetPhysSignal psig1, psig2, psig3, psig4;
    JPetHit hit1, hit2;

    string osc_file = (*fIt).second;
    string filename;

    int tslot_index;
    sscanf(path(osc_file).filename().string().c_str(), "%*3s %d", &tslot_index);

    //INFO (Form("Processing file: %s", osc_file.c_str()));
    JPetRecoSignal& rsig1 = fReader.generateSignal(osc_file.c_str());
    rsig1.setPM(*(fConfig.ppm1));
    rsig1.setTSlotIndex(tslot_index);
    psig1.setRecoSignal(rsig1);

    filename = path((*fIt).second).filename().string();
    filename[1] = (fConfig.file2)[1];
    osc_file = path((*fIt).second).parent_path().string();
    osc_file+= "/";
    osc_file+= filename;

    //INFO (Form("Processing file: %s", osc_file.c_str()));
    JPetRecoSignal& rsig2 = fReader.generateSignal(osc_file.c_str());
    rsig2.setPM(*(fConfig.ppm2));
    rsig2.setTSlotIndex(tslot_index);
    psig2.setRecoSignal(rsig2);

    filename = path((*fIt).second).filename().string();
    filename[1] = (fConfig.file3)[1];
    osc_file = path((*fIt).second).parent_path().string();
    osc_file+= "/";
    osc_file+= filename;

    //INFO (Form("Processing file: %s", osc_file.c_str()));
    JPetRecoSignal& rsig3 = fReader.generateSignal(osc_file.c_str());
    rsig3.setPM(*(fConfig.ppm3));
    rsig3.setTSlotIndex(tslot_index);
    psig3.setRecoSignal(rsig3);

    filename = path((*fIt).second).filename().string();
    filename[1] = (fConfig.file4)[1];
    osc_file  = path((*fIt).second).parent_path().string();
    osc_file += "/";
    osc_file += filename;

    //INFO (Form("Processing file: %s", osc_file.c_str()));
    JPetRecoSignal& rsig4 = fReader.generateSignal(osc_file.c_str());
    rsig4.setPM(*(fConfig.ppm4));
    rsig4.setTSlotIndex(tslot_index);
    psig4.setRecoSignal(rsig4);

    hit1.setSignals(psig1, psig2);
    hit1.setScinID(fConfig.scin1);

    hit2.setSignals(psig3, psig4);
    hit2.setScinID(fConfig.scin2);

    JPetLOR event;

    event.setHits(hit1, hit2);

    fWriter->write(event);

    break;
  }
  fIt++;
}

void JPetScopeModule::terminate() {
//  assert(fWriter);
  if(fWriter)
  if(fWriter->isOpen()) {
    //std::cout <<"in JPetScope terminate()" <<std::endl;
    fWriter->closeFile();
    delete fWriter;
    fWriter = 0;
  }
}

void JPetScopeModule::printCollPositions () {
  INFO ("Printing all collimator positions:");
  for (set<int>::iterator iter = fCollPositions.begin(); iter != fCollPositions.end(); ++iter) {
    INFO (Form("collimator position: %d", *iter));
  }
}

void JPetScopeModule::printFiles () {
  INFO ("Printing all files:");
  for (map<int, string>::iterator iter = fFiles.begin(); iter != fFiles.end(); ++iter) {
    INFO (Form("%3d %s", (*iter).first, (*iter).second.c_str()));
  }
}

void JPetScopeModule::setFileName(const char* name)
{
  fInFilename = TString(name);
  fOutFilename = TString(name);
  fOutFilename.ReplaceAll(".cfg", "");
  fOutFilename.Append(".scope.eve.root");
}
<|endoftext|>


<commit_before>#include "Runtime/World/CScriptSound.hpp"

#include "Runtime/CStateManager.hpp"
#include "Runtime/Character/CModelData.hpp"
#include "Runtime/Collision/CMaterialList.hpp"
#include "Runtime/World/CActorParameters.hpp"
#include "Runtime/World/CWorld.hpp"

#include "TCastTo.hpp" // Generated file, do not modify include path

namespace urde {
bool CScriptSound::sFirstInFrame = false;

CScriptSound::CScriptSound(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf,
                           u16 soundId, bool active, float maxDist, float distComp, float startDelay, u32 minVol,
                           u32 vol, u32 w3, u32 prio, u32 pan, u32 w6, bool looped, bool nonEmitter, bool autoStart,
                           bool occlusionTest, bool acoustics, bool worldSfx, bool allowDuplicates, s32 pitch)
: CActor(uid, active, name, info, xf, CModelData::CModelDataNull(), CMaterialList(EMaterialTypes::NoStepLogic),
         CActorParameters::None(), kInvalidUniqueId)
, xfc_startDelay(startDelay)
, x100_soundId(CSfxManager::TranslateSFXID(soundId))
, x104_maxDist(maxDist)
, x108_distComp(distComp)
, x10c_minVol(minVol / 127.f)
, x10e_vol(vol / 127.f)
, x110_(w3)
, x112_prio(s16(prio))
, x114_pan(pan / 64.f - 1.f)
, x116_(w6)
, x118_pitch(pitch / 8192.f)
, x11c_25_looped(looped)
, x11c_26_nonEmitter(nonEmitter)
, x11c_27_autoStart(autoStart)
, x11c_28_occlusionTest(occlusionTest)
, x11c_29_acoustics(acoustics)
, x11c_30_worldSfx(worldSfx)
, x11d_24_allowDuplicates(allowDuplicates) {
  if (x11c_30_worldSfx && (!x11c_26_nonEmitter || !x11c_25_looped))
    x11c_30_worldSfx = false;
}

void CScriptSound::Accept(IVisitor& visitor) { visitor.Visit(this); }

void CScriptSound::PreThink(float dt, CStateManager& mgr) {
  CEntity::PreThink(dt, mgr);
  sFirstInFrame = true;
  x11d_25_processedThisFrame = false;
}

constexpr CMaterialFilter kSolidFilter =
    CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {EMaterialTypes::ProjectilePassthrough});

float CScriptSound::GetOccludedVolumeAmount(const zeus::CVector3f& pos, const CStateManager& mgr) {
  zeus::CTransform camXf = mgr.GetCameraManager()->GetCurrentCameraTransform(mgr);
  zeus::CVector3f soundToCam = camXf.origin - pos;
  float soundToCamMag = soundToCam.magnitude();
  zeus::CVector3f soundToCamNorm = soundToCam * (1.f / soundToCamMag);
  zeus::CVector3f thirdEdge = zeus::skUp - soundToCamNorm * soundToCamNorm.dot(zeus::skUp);
  zeus::CVector3f cross = soundToCamNorm.cross(thirdEdge);
  static float kInfluenceAmount = 3.f / soundToCamMag;
  static float kInfluenceIncrement = kInfluenceAmount;

  int totalCount = 0;
  int invalCount = 0;
  float f17 = -kInfluenceAmount;
  while (f17 <= kInfluenceAmount) {
    zeus::CVector3f angledDir = thirdEdge * f17 + soundToCamNorm;
    float f16 = -kInfluenceAmount;
    while (f16 <= kInfluenceAmount) {
      if (mgr.RayStaticIntersection(pos, (cross * f16 + angledDir).normalized(), soundToCamMag, kSolidFilter)
              .IsInvalid())
        ++invalCount;
      ++totalCount;
      f16 += kInfluenceIncrement;
    }
    f17 += kInfluenceIncrement;
  }

  return invalCount / float(totalCount) * 0.42f + 0.58f;
}

void CScriptSound::Think(float dt, CStateManager& mgr) {
  if (x11c_31_selfFree && (!GetActive() || x11c_25_looped || !x11c_27_autoStart)) {
    mgr.FreeScriptObject(GetUniqueId());
  } else if (GetActive()) {
    if (!x11c_25_looped && x11c_27_autoStart && !x11c_24_playRequested && xec_sfxHandle &&
        !CSfxManager::IsPlaying(xec_sfxHandle))
      mgr.FreeScriptObject(GetUniqueId());

    if (!x11c_26_nonEmitter && xec_sfxHandle) {
      if (xf8_updateTimer <= 0.f) {
        xf8_updateTimer = 0.25f;
        CSfxManager::UpdateEmitter(xec_sfxHandle, GetTranslation(), zeus::skZero3f, xf2_maxVolUpd);
      } else {
        xf8_updateTimer -= dt;
      }
    }

    if (xec_sfxHandle && !x11c_26_nonEmitter && x11c_28_occlusionTest) {
      if (xe8_occUpdateTimer <= 0.f && sFirstInFrame) {
        sFirstInFrame = false;
        float occVol = GetOccludedVolumeAmount(GetTranslation(), mgr);
        float newMaxVol = std::max(occVol * x10e_vol, x10c_minVol);
        if (newMaxVol != xf0_maxVol) {
          xf0_maxVol = newMaxVol;
          float delta = xf0_maxVol - xf2_maxVolUpd;
          xf4_maxVolUpdDelta = delta / 10.5f;
          if (xf4_maxVolUpdDelta == 0.f) {
            if (xf2_maxVolUpd < xf0_maxVol)
              xf4_maxVolUpdDelta = 1.f / 127.f;
            else
              xf4_maxVolUpdDelta = -1.f / 127.f;
          }
        }
        xe8_occUpdateTimer = 0.5f;
      } else {
        xe8_occUpdateTimer -= dt;
      }

      if (xf2_maxVolUpd != xf0_maxVol) {
        xf2_maxVolUpd += xf4_maxVolUpdDelta;
        if (xf4_maxVolUpdDelta > 0.f && xf2_maxVolUpd > xf0_maxVol)
          xf2_maxVolUpd = xf0_maxVol;
        if (xf4_maxVolUpdDelta < 0.f && xf2_maxVolUpd < xf0_maxVol)
          xf2_maxVolUpd = xf0_maxVol;
        CSfxManager::UpdateEmitter(xec_sfxHandle, GetTranslation(), zeus::skZero3f, xf2_maxVolUpd);
      }
    }

    if (x11c_24_playRequested) {
      xfc_startDelay -= dt;
      if (xfc_startDelay <= 0.f) {
        x11c_24_playRequested = false;
        PlaySound(mgr);
      }
    }

    if (x118_pitch != 0.f && xec_sfxHandle)
      CSfxManager::PitchBend(xec_sfxHandle, x118_pitch);
  }
}

void CScriptSound::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) {
  CActor::AcceptScriptMsg(msg, uid, mgr);

  switch (msg) {
  case EScriptObjectMessage::Registered: {
    if (GetActive() && x11c_27_autoStart)
      x11c_24_playRequested = true;
    x11c_31_selfFree = mgr.GetIsGeneratingObject();
  } break;
  case EScriptObjectMessage::Play: {
    if (GetActive())
      PlaySound(mgr);
  } break;
  case EScriptObjectMessage::Stop: {
    if (GetActive())
      StopSound(mgr);
  } break;
  case EScriptObjectMessage::Deactivate: {
    StopSound(mgr);
  } break;
  case EScriptObjectMessage::Activate: {
    if (GetActive())
      x11c_24_playRequested = true;
  } break;
  case EScriptObjectMessage::Deleted: {
    if (!x11c_30_worldSfx)
      StopSound(mgr);
  } break;
  default:
    break;
  }
}

void CScriptSound::PlaySound(CStateManager& mgr) {
  if ((x11d_24_allowDuplicates || !xec_sfxHandle || xec_sfxHandle->IsClosed()) && !x11d_25_processedThisFrame) {
    x11d_25_processedThisFrame = true;
    if (x11c_26_nonEmitter) {
      if (!x11c_30_worldSfx || !mgr.GetWorld()->HasGlobalSound(x100_soundId)) {
        xec_sfxHandle = CSfxManager::SfxStart(x100_soundId, x10e_vol, x114_pan, x11c_29_acoustics, x112_prio,
                                              x11c_25_looped, x11c_30_worldSfx ? kInvalidAreaId : GetAreaIdAlways());
        if (x11c_30_worldSfx)
          mgr.GetWorld()->AddGlobalSound(xec_sfxHandle);
      }
    } else {
      float occVol = x11c_28_occlusionTest ? GetOccludedVolumeAmount(GetTranslation(), mgr) : 1.f;
      xf0_maxVol = xf2_maxVolUpd = x10e_vol * occVol;
      CAudioSys::C3DEmitterParmData data = {};
      data.x0_pos = GetTranslation();
      data.x18_maxDist = x104_maxDist;
      data.x1c_distComp = x108_distComp;
      data.x20_flags = 1; // Continuous parameter update
      data.x24_sfxId = x100_soundId;
      data.x26_maxVol = xf0_maxVol;
      data.x27_minVol = x10c_minVol;
      data.x29_prio = 0x7f;
      xec_sfxHandle = CSfxManager::AddEmitter(data, x11c_29_acoustics, x112_prio, x11c_25_looped, GetAreaIdAlways());
    }
  }
}

void CScriptSound::StopSound(CStateManager& mgr) {
  x11c_24_playRequested = false;
  if (x11c_30_worldSfx && x11c_26_nonEmitter) {
    mgr.GetWorld()->StopGlobalSound(x100_soundId);
    xec_sfxHandle.reset();
  } else if (xec_sfxHandle) {
    CSfxManager::RemoveEmitter(xec_sfxHandle);
    xec_sfxHandle.reset();
  }
}
} // namespace urde
<commit_msg>CScriptSound: Brace conditionals where applicable<commit_after>#include "Runtime/World/CScriptSound.hpp"

#include "Runtime/CStateManager.hpp"
#include "Runtime/Character/CModelData.hpp"
#include "Runtime/Collision/CMaterialList.hpp"
#include "Runtime/World/CActorParameters.hpp"
#include "Runtime/World/CWorld.hpp"

#include "TCastTo.hpp" // Generated file, do not modify include path

namespace urde {
bool CScriptSound::sFirstInFrame = false;

CScriptSound::CScriptSound(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf,
                           u16 soundId, bool active, float maxDist, float distComp, float startDelay, u32 minVol,
                           u32 vol, u32 w3, u32 prio, u32 pan, u32 w6, bool looped, bool nonEmitter, bool autoStart,
                           bool occlusionTest, bool acoustics, bool worldSfx, bool allowDuplicates, s32 pitch)
: CActor(uid, active, name, info, xf, CModelData::CModelDataNull(), CMaterialList(EMaterialTypes::NoStepLogic),
         CActorParameters::None(), kInvalidUniqueId)
, xfc_startDelay(startDelay)
, x100_soundId(CSfxManager::TranslateSFXID(soundId))
, x104_maxDist(maxDist)
, x108_distComp(distComp)
, x10c_minVol(minVol / 127.f)
, x10e_vol(vol / 127.f)
, x110_(w3)
, x112_prio(s16(prio))
, x114_pan(pan / 64.f - 1.f)
, x116_(w6)
, x118_pitch(pitch / 8192.f)
, x11c_25_looped(looped)
, x11c_26_nonEmitter(nonEmitter)
, x11c_27_autoStart(autoStart)
, x11c_28_occlusionTest(occlusionTest)
, x11c_29_acoustics(acoustics)
, x11c_30_worldSfx(worldSfx)
, x11d_24_allowDuplicates(allowDuplicates) {
  if (x11c_30_worldSfx && (!x11c_26_nonEmitter || !x11c_25_looped)) {
    x11c_30_worldSfx = false;
  }
}

void CScriptSound::Accept(IVisitor& visitor) { visitor.Visit(this); }

void CScriptSound::PreThink(float dt, CStateManager& mgr) {
  CEntity::PreThink(dt, mgr);
  sFirstInFrame = true;
  x11d_25_processedThisFrame = false;
}

constexpr CMaterialFilter kSolidFilter =
    CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {EMaterialTypes::ProjectilePassthrough});

float CScriptSound::GetOccludedVolumeAmount(const zeus::CVector3f& pos, const CStateManager& mgr) {
  const zeus::CTransform camXf = mgr.GetCameraManager()->GetCurrentCameraTransform(mgr);
  const zeus::CVector3f soundToCam = camXf.origin - pos;
  const float soundToCamMag = soundToCam.magnitude();
  const zeus::CVector3f soundToCamNorm = soundToCam * (1.f / soundToCamMag);
  const zeus::CVector3f thirdEdge = zeus::skUp - soundToCamNorm * soundToCamNorm.dot(zeus::skUp);
  const zeus::CVector3f cross = soundToCamNorm.cross(thirdEdge);
  static float kInfluenceAmount = 3.f / soundToCamMag;
  static float kInfluenceIncrement = kInfluenceAmount;

  int totalCount = 0;
  int invalCount = 0;
  float f17 = -kInfluenceAmount;
  while (f17 <= kInfluenceAmount) {
    const zeus::CVector3f angledDir = thirdEdge * f17 + soundToCamNorm;
    float f16 = -kInfluenceAmount;
    while (f16 <= kInfluenceAmount) {
      if (mgr.RayStaticIntersection(pos, (cross * f16 + angledDir).normalized(), soundToCamMag, kSolidFilter)
              .IsInvalid()) {
        ++invalCount;
      }
      ++totalCount;
      f16 += kInfluenceIncrement;
    }
    f17 += kInfluenceIncrement;
  }

  return invalCount / float(totalCount) * 0.42f + 0.58f;
}

void CScriptSound::Think(float dt, CStateManager& mgr) {
  if (x11c_31_selfFree && (!GetActive() || x11c_25_looped || !x11c_27_autoStart)) {
    mgr.FreeScriptObject(GetUniqueId());
  } else if (GetActive()) {
    if (!x11c_25_looped && x11c_27_autoStart && !x11c_24_playRequested && xec_sfxHandle &&
        !CSfxManager::IsPlaying(xec_sfxHandle)) {
      mgr.FreeScriptObject(GetUniqueId());
    }

    if (!x11c_26_nonEmitter && xec_sfxHandle) {
      if (xf8_updateTimer <= 0.f) {
        xf8_updateTimer = 0.25f;
        CSfxManager::UpdateEmitter(xec_sfxHandle, GetTranslation(), zeus::skZero3f, xf2_maxVolUpd);
      } else {
        xf8_updateTimer -= dt;
      }
    }

    if (xec_sfxHandle && !x11c_26_nonEmitter && x11c_28_occlusionTest) {
      if (xe8_occUpdateTimer <= 0.f && sFirstInFrame) {
        sFirstInFrame = false;
        const float occVol = GetOccludedVolumeAmount(GetTranslation(), mgr);
        const float newMaxVol = std::max(occVol * x10e_vol, x10c_minVol);
        if (newMaxVol != xf0_maxVol) {
          xf0_maxVol = newMaxVol;
          const float delta = xf0_maxVol - xf2_maxVolUpd;
          xf4_maxVolUpdDelta = delta / 10.5f;
          if (xf4_maxVolUpdDelta == 0.f) {
            if (xf2_maxVolUpd < xf0_maxVol) {
              xf4_maxVolUpdDelta = 1.f / 127.f;
            } else {
              xf4_maxVolUpdDelta = -1.f / 127.f;
            }
          }
        }
        xe8_occUpdateTimer = 0.5f;
      } else {
        xe8_occUpdateTimer -= dt;
      }

      if (xf2_maxVolUpd != xf0_maxVol) {
        xf2_maxVolUpd += xf4_maxVolUpdDelta;
        if (xf4_maxVolUpdDelta > 0.f && xf2_maxVolUpd > xf0_maxVol) {
          xf2_maxVolUpd = xf0_maxVol;
        }
        if (xf4_maxVolUpdDelta < 0.f && xf2_maxVolUpd < xf0_maxVol) {
          xf2_maxVolUpd = xf0_maxVol;
        }
        CSfxManager::UpdateEmitter(xec_sfxHandle, GetTranslation(), zeus::skZero3f, xf2_maxVolUpd);
      }
    }

    if (x11c_24_playRequested) {
      xfc_startDelay -= dt;
      if (xfc_startDelay <= 0.f) {
        x11c_24_playRequested = false;
        PlaySound(mgr);
      }
    }

    if (x118_pitch != 0.f && xec_sfxHandle) {
      CSfxManager::PitchBend(xec_sfxHandle, x118_pitch);
    }
  }
}

void CScriptSound::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) {
  CActor::AcceptScriptMsg(msg, uid, mgr);

  switch (msg) {
  case EScriptObjectMessage::Registered: {
    if (GetActive() && x11c_27_autoStart) {
      x11c_24_playRequested = true;
    }
    x11c_31_selfFree = mgr.GetIsGeneratingObject();
  } break;
  case EScriptObjectMessage::Play: {
    if (GetActive()) {
      PlaySound(mgr);
    }
  } break;
  case EScriptObjectMessage::Stop: {
    if (GetActive()) {
      StopSound(mgr);
    }
  } break;
  case EScriptObjectMessage::Deactivate: {
    StopSound(mgr);
  } break;
  case EScriptObjectMessage::Activate: {
    if (GetActive()) {
      x11c_24_playRequested = true;
    }
  } break;
  case EScriptObjectMessage::Deleted: {
    if (!x11c_30_worldSfx) {
      StopSound(mgr);
    }
  } break;
  default:
    break;
  }
}

void CScriptSound::PlaySound(CStateManager& mgr) {
  if (!x11d_24_allowDuplicates && xec_sfxHandle && !xec_sfxHandle->IsClosed() || x11d_25_processedThisFrame) {
    return;
  }

  x11d_25_processedThisFrame = true;
  if (x11c_26_nonEmitter) {
    if (!x11c_30_worldSfx || !mgr.GetWorld()->HasGlobalSound(x100_soundId)) {
      xec_sfxHandle = CSfxManager::SfxStart(x100_soundId, x10e_vol, x114_pan, x11c_29_acoustics, x112_prio,
                                            x11c_25_looped, x11c_30_worldSfx ? kInvalidAreaId : GetAreaIdAlways());
      if (x11c_30_worldSfx) {
        mgr.GetWorld()->AddGlobalSound(xec_sfxHandle);
      }
    }
  } else {
    const float occVol = x11c_28_occlusionTest ? GetOccludedVolumeAmount(GetTranslation(), mgr) : 1.f;
    xf0_maxVol = xf2_maxVolUpd = x10e_vol * occVol;
    CAudioSys::C3DEmitterParmData data = {};
    data.x0_pos = GetTranslation();
    data.x18_maxDist = x104_maxDist;
    data.x1c_distComp = x108_distComp;
    data.x20_flags = 1; // Continuous parameter update
    data.x24_sfxId = x100_soundId;
    data.x26_maxVol = xf0_maxVol;
    data.x27_minVol = x10c_minVol;
    data.x29_prio = 0x7f;
    xec_sfxHandle = CSfxManager::AddEmitter(data, x11c_29_acoustics, x112_prio, x11c_25_looped, GetAreaIdAlways());
  }
}

void CScriptSound::StopSound(CStateManager& mgr) {
  x11c_24_playRequested = false;
  if (x11c_30_worldSfx && x11c_26_nonEmitter) {
    mgr.GetWorld()->StopGlobalSound(x100_soundId);
    xec_sfxHandle.reset();
  } else if (xec_sfxHandle) {
    CSfxManager::RemoveEmitter(xec_sfxHandle);
    xec_sfxHandle.reset();
  }
}
} // namespace urde
<|endoftext|>


<commit_before>// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp

#include <Nazara/Core/Error.hpp>
#include <type_traits>

namespace Ndk
{
	inline BaseSystem::BaseSystem(SystemIndex systemId) :
	m_systemIndex(systemId)
	{
		SetUpdateRate(30);
	}

	inline BaseSystem::BaseSystem(const BaseSystem& system) :
	m_excludedComponents(system.m_excludedComponents),
	m_requiredComponents(system.m_requiredComponents),
	m_systemIndex(system.m_systemIndex),
	m_updateCounter(0.f),
	m_updateRate(system.m_updateRate)
	{
	}

	inline const std::vector<EntityHandle>& BaseSystem::GetEntities() const
	{
		return m_entities;
	}

	inline SystemIndex BaseSystem::GetIndex() const
	{
		return m_systemIndex;
	}

	inline float BaseSystem::GetUpdateRate() const
	{
		return 1.f / m_updateRate;
	}

	inline World& BaseSystem::GetWorld() const
	{
		return *m_world;
	}

	inline bool BaseSystem::HasEntity(const Entity* entity) const
	{
		if (!entity)
			return false;

		return m_entityBits.UnboundedTest(entity->GetId());
	}

	inline void BaseSystem::SetUpdateRate(float updatePerSecond)
	{
		m_updateCounter = 0.f;
		m_updateRate = (updatePerSecond > 0.f) ? 1.f / updatePerSecond : 0.f; // 0.f means no limit
	}

	inline void BaseSystem::Update(float elapsedTime)
	{
		m_updateCounter -= elapsedTime;
		if (m_updateCounter < 0.f)
		{
			m_updateCounter += m_updateRate;
			OnUpdate(elapsedTime);
		}
	}

	template<typename ComponentType>
	void BaseSystem::Excludes()
	{
		static_assert(std::is_base_of<BaseComponent, ComponentType>::value , "ComponentType is not a component");

		ExcludesComponent(GetComponentIndex<ComponentType>());
	}

	template<typename ComponentType1, typename ComponentType2, typename... Rest>
	void BaseSystem::Excludes()
	{
		Excludes<ComponentType1>();
		Excludes<ComponentType2, Rest...>();
	}

	inline void BaseSystem::ExcludesComponent(ComponentIndex index)
	{
		m_excludedComponents.UnboundedSet(index);
	}

	inline SystemIndex BaseSystem::GetNextIndex()
	{
		return s_nextIndex++;
	}

	template<typename ComponentType>
	void BaseSystem::Requires()
	{
		static_assert(std::is_base_of<BaseComponent, ComponentType>::value, "ComponentType is not a component");

		RequiresComponent(GetComponentIndex<ComponentType>());
	}

	template<typename ComponentType1, typename ComponentType2, typename... Rest>
	void BaseSystem::Requires()
	{
		Requires<ComponentType1>();
		Requires<ComponentType2, Rest...>();
	}

	inline void BaseSystem::RequiresComponent(ComponentIndex index)
	{
		m_requiredComponents.UnboundedSet(index);
	}

	template<typename ComponentType>
	void BaseSystem::RequiresAny()
	{
		static_assert(std::is_base_of<BaseComponent, ComponentType>::value, "ComponentType is not a component");

		RequiresAnyComponent(GetComponentIndex<ComponentType>());
	}

	template<typename ComponentType1, typename ComponentType2, typename... Rest>
	void BaseSystem::RequiresAny()
	{
		RequiresAny<ComponentType1>();
		RequiresAny<ComponentType2, Rest...>();
	}

	inline void BaseSystem::RequiresAnyComponent(ComponentIndex index)
	{
		m_requiredAnyComponents.UnboundedSet(index);
	}

	inline void BaseSystem::AddEntity(Entity* entity)
	{
		NazaraAssert(entity, "Invalid entity");

		m_entities.emplace_back(entity);
		m_entityBits.UnboundedSet(entity->GetId(), true);

		entity->RegisterSystem(m_systemIndex);

		OnEntityAdded(entity);
	}

	inline void BaseSystem::RemoveEntity(Entity* entity)
	{
		NazaraAssert(entity, "Invalid entity");

		auto it = std::find(m_entities.begin(), m_entities.end(), *entity);
		NazaraAssert(it != m_entities.end(), "Entity is not part of this system");

		// Pour éviter de déplacer beaucoup de handles, on swap le dernier avec celui à supprimer
		std::swap(*it, m_entities.back());
		m_entities.pop_back(); // On le sort du vector

		m_entityBits.Reset(entity->GetId());
		entity->UnregisterSystem(m_systemIndex);

		OnEntityRemoved(entity); // Et on appelle le callback
	}

	inline void BaseSystem::ValidateEntity(Entity* entity, bool justAdded)
	{
		NazaraAssert(entity, "Invalid entity");
		NazaraAssert(HasEntity(entity), "Entity should be part of system");

		OnEntityValidation(entity, justAdded);
	}

	inline void BaseSystem::SetWorld(World& world)
	{
		m_world = &world;
	}

	inline bool BaseSystem::Initialize()
	{
		s_nextIndex = 0;

		return true;
	}

	inline void BaseSystem::Uninitialize()
	{
		// Rien à faire
	}
}
<commit_msg>Sdk/BaseSystem: Fix update rate of 0<commit_after>// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp

#include <Nazara/Core/Error.hpp>
#include <type_traits>

namespace Ndk
{
	inline BaseSystem::BaseSystem(SystemIndex systemId) :
	m_systemIndex(systemId)
	{
		SetUpdateRate(30);
	}

	inline BaseSystem::BaseSystem(const BaseSystem& system) :
	m_excludedComponents(system.m_excludedComponents),
	m_requiredComponents(system.m_requiredComponents),
	m_systemIndex(system.m_systemIndex),
	m_updateCounter(0.f),
	m_updateRate(system.m_updateRate)
	{
	}

	inline const std::vector<EntityHandle>& BaseSystem::GetEntities() const
	{
		return m_entities;
	}

	inline SystemIndex BaseSystem::GetIndex() const
	{
		return m_systemIndex;
	}

	inline float BaseSystem::GetUpdateRate() const
	{
		return (m_updateRate > 0.f) ? 1.f / m_updateRate : 0.f;
	}

	inline World& BaseSystem::GetWorld() const
	{
		return *m_world;
	}

	inline bool BaseSystem::HasEntity(const Entity* entity) const
	{
		if (!entity)
			return false;

		return m_entityBits.UnboundedTest(entity->GetId());
	}

	inline void BaseSystem::SetUpdateRate(float updatePerSecond)
	{
		m_updateCounter = 0.f;
		m_updateRate = (updatePerSecond > 0.f) ? 1.f / updatePerSecond : 0.f; // 0.f means no limit
	}

	inline void BaseSystem::Update(float elapsedTime)
	{
		if (m_updateRate > 0.f)
		{
			m_updateCounter -= elapsedTime;
			if (m_updateCounter >= 0.f)
				return;

			m_updateCounter += m_updateRate;
		}

		OnUpdate(elapsedTime);
	}

	template<typename ComponentType>
	void BaseSystem::Excludes()
	{
		static_assert(std::is_base_of<BaseComponent, ComponentType>::value , "ComponentType is not a component");

		ExcludesComponent(GetComponentIndex<ComponentType>());
	}

	template<typename ComponentType1, typename ComponentType2, typename... Rest>
	void BaseSystem::Excludes()
	{
		Excludes<ComponentType1>();
		Excludes<ComponentType2, Rest...>();
	}

	inline void BaseSystem::ExcludesComponent(ComponentIndex index)
	{
		m_excludedComponents.UnboundedSet(index);
	}

	inline SystemIndex BaseSystem::GetNextIndex()
	{
		return s_nextIndex++;
	}

	template<typename ComponentType>
	void BaseSystem::Requires()
	{
		static_assert(std::is_base_of<BaseComponent, ComponentType>::value, "ComponentType is not a component");

		RequiresComponent(GetComponentIndex<ComponentType>());
	}

	template<typename ComponentType1, typename ComponentType2, typename... Rest>
	void BaseSystem::Requires()
	{
		Requires<ComponentType1>();
		Requires<ComponentType2, Rest...>();
	}

	inline void BaseSystem::RequiresComponent(ComponentIndex index)
	{
		m_requiredComponents.UnboundedSet(index);
	}

	template<typename ComponentType>
	void BaseSystem::RequiresAny()
	{
		static_assert(std::is_base_of<BaseComponent, ComponentType>::value, "ComponentType is not a component");

		RequiresAnyComponent(GetComponentIndex<ComponentType>());
	}

	template<typename ComponentType1, typename ComponentType2, typename... Rest>
	void BaseSystem::RequiresAny()
	{
		RequiresAny<ComponentType1>();
		RequiresAny<ComponentType2, Rest...>();
	}

	inline void BaseSystem::RequiresAnyComponent(ComponentIndex index)
	{
		m_requiredAnyComponents.UnboundedSet(index);
	}

	inline void BaseSystem::AddEntity(Entity* entity)
	{
		NazaraAssert(entity, "Invalid entity");

		m_entities.emplace_back(entity);
		m_entityBits.UnboundedSet(entity->GetId(), true);

		entity->RegisterSystem(m_systemIndex);

		OnEntityAdded(entity);
	}

	inline void BaseSystem::RemoveEntity(Entity* entity)
	{
		NazaraAssert(entity, "Invalid entity");

		auto it = std::find(m_entities.begin(), m_entities.end(), *entity);
		NazaraAssert(it != m_entities.end(), "Entity is not part of this system");

		// Pour éviter de déplacer beaucoup de handles, on swap le dernier avec celui à supprimer
		std::swap(*it, m_entities.back());
		m_entities.pop_back(); // On le sort du vector

		m_entityBits.Reset(entity->GetId());
		entity->UnregisterSystem(m_systemIndex);

		OnEntityRemoved(entity); // Et on appelle le callback
	}

	inline void BaseSystem::ValidateEntity(Entity* entity, bool justAdded)
	{
		NazaraAssert(entity, "Invalid entity");
		NazaraAssert(HasEntity(entity), "Entity should be part of system");

		OnEntityValidation(entity, justAdded);
	}

	inline void BaseSystem::SetWorld(World& world)
	{
		m_world = &world;
	}

	inline bool BaseSystem::Initialize()
	{
		s_nextIndex = 0;

		return true;
	}

	inline void BaseSystem::Uninitialize()
	{
		// Rien à faire
	}
}
<|endoftext|>


<commit_before>// Copyright (C) 2016 Jrme Leclercq, Arnaud Cadot
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp

#include <NDK/LuaBinding.hpp>
#include <NDK/LuaAPI.hpp>

namespace Ndk
{
	/*!
	* \brief Binds SDK module to Lua
	*/

	void LuaBinding::BindSDK()
	{
		/*********************************** Ndk::Application **********************************/

		#ifndef NDK_SERVER
		//application.SetMethod("AddWindow", &Application::AddWindow);
		#endif
		application.BindMethod("AddWorld", [] (Nz::LuaInstance& instance, Application* application) -> int
		{
			instance.Push(application->AddWorld().CreateHandle());
			return 1;
		});

		application.BindMethod("GetUpdateTime", &Application::GetUpdateTime);
		application.BindMethod("Quit", &Application::Quit);

		/*********************************** Ndk::Console **********************************/
		#ifndef NDK_SERVER
		consoleClass.Inherit<Nz::Node>(nodeClass, [] (ConsoleHandle* handle) -> Nz::Node*
		{
			return handle->GetObject();
		});

		consoleClass.BindMethod("AddLine", &Console::AddLine, Nz::Color::White);
		consoleClass.BindMethod("Clear", &Console::Clear);
		consoleClass.BindMethod("GetCharacterSize", &Console::GetCharacterSize);
		consoleClass.BindMethod("GetHistory", &Console::GetHistory);
		consoleClass.BindMethod("GetHistoryBackground", &Console::GetHistoryBackground);
		consoleClass.BindMethod("GetInput", &Console::GetInput);
		consoleClass.BindMethod("GetInputBackground", &Console::GetInputBackground);
		consoleClass.BindMethod("GetSize", &Console::GetSize);
		consoleClass.BindMethod("GetTextFont", &Console::GetTextFont);

		consoleClass.BindMethod("IsVisible", &Console::IsVisible);

		consoleClass.BindMethod("SendCharacter", &Console::SendCharacter);
		//consoleClass.SetMethod("SendEvent", &Console::SendEvent);

		consoleClass.BindMethod("SetCharacterSize", &Console::SetCharacterSize);
		consoleClass.BindMethod("SetSize", &Console::SetSize);
		consoleClass.BindMethod("SetTextFont", &Console::SetTextFont);

		consoleClass.BindMethod("Show", &Console::Show, true);
		#endif

		/*********************************** Ndk::Entity **********************************/
		entityClass.BindMethod("Enable", &Entity::Enable);
		entityClass.BindMethod("GetId", &Entity::GetId);
		entityClass.BindMethod("GetWorld", &Entity::GetWorld);
		entityClass.BindMethod("Kill", &Entity::Kill);
		entityClass.BindMethod("IsEnabled", &Entity::IsEnabled);
		entityClass.BindMethod("IsValid", &Entity::IsValid);
		entityClass.BindMethod("RemoveAllComponents", &Entity::RemoveAllComponents);
		entityClass.BindMethod("__tostring", &EntityHandle::ToString);

		entityClass.BindMethod("AddComponent", [this] (Nz::LuaInstance& instance, EntityHandle& handle) -> int
		{
			ComponentBinding* binding = QueryComponentIndex(instance);

			return binding->adder(instance, handle);
		});

		entityClass.BindMethod("GetComponent", [this] (Nz::LuaInstance& instance, EntityHandle& handle) -> int
		{
			ComponentBinding* binding = QueryComponentIndex(instance);

			return binding->getter(instance, handle->GetComponent(binding->index));
		});

		entityClass.BindMethod("RemoveComponent", [this] (Nz::LuaInstance& instance, EntityHandle& handle) -> int
		{
			ComponentBinding* binding = QueryComponentIndex(instance);

			handle->RemoveComponent(binding->index);
			return 0;
		});

		/*********************************** Ndk::NodeComponent **********************************/
		nodeComponent.Inherit<Nz::Node>(nodeClass, [] (NodeComponentHandle* handle) -> Nz::Node*
		{
			return handle->GetObject();
		});

		/*********************************** Ndk::VelocityComponent **********************************/
		velocityComponent.SetGetter([] (Nz::LuaInstance& lua, VelocityComponentHandle& instance)
		{
			std::size_t length;
			const char* member = lua.CheckString(1, &length);

			if (std::strcmp(member, "Linear") == 0)
			{
				lua.Push(instance->linearVelocity);
				return true;
			}

			return false;
		});

		velocityComponent.SetSetter([] (Nz::LuaInstance& lua, VelocityComponentHandle& instance)
		{
			std::size_t length;
			const char* member = lua.CheckString(1, &length);

			int argIndex = 2;
			if (std::strcmp(member, "Linear") == 0)
			{
				instance->linearVelocity = lua.Check<Nz::Vector3f>(&argIndex);
				return true;
			}

			return false;
		});

		/*********************************** Ndk::World **********************************/
		worldClass.BindMethod("CreateEntity", &World::CreateEntity);
		worldClass.BindMethod("CreateEntities", &World::CreateEntities);
		worldClass.BindMethod("Clear", &World::Clear);

		#ifndef NDK_SERVER
		/*********************************** Ndk::GraphicsComponent **********************************/
		graphicsComponent.BindMethod("Attach", &GraphicsComponent::Attach, 0);
		#endif

		// Components functions
		m_componentBinding.resize(BaseComponent::GetMaxComponentIndex());

		BindComponent<NodeComponent>("Node");
		BindComponent<VelocityComponent>("Velocity");

		#ifndef NDK_SERVER
		BindComponent<GraphicsComponent>("Graphics");
		#endif
	}

	/*!
	* \brief Registers the classes that will be used by the Lua instance
	*
	* \param instance Lua instance that will interact with the SDK classes
	*/

	void LuaBinding::RegisterSDK(Nz::LuaInstance& instance)
	{
		// Classes
		application.Register(instance);
		entityClass.Register(instance);
		nodeComponent.Register(instance);
		velocityComponent.Register(instance);
		worldClass.Register(instance);

		#ifndef NDK_SERVER
		consoleClass.Register(instance);
		graphicsComponent.Register(instance);
		#endif

		// Enums

		// ComponentType (fake enumeration to expose component indexes)
		instance.PushTable(0, m_componentBinding.size());
		{
			for (const ComponentBinding& entry : m_componentBinding)
			{
				if (entry.name.IsEmpty())
					continue;

				instance.PushField(entry.name, entry.index);
			}
		}
		instance.SetGlobal("ComponentType");
	}

	/*!
	* \brief Gets the index of the component
	* \return A pointer to the binding linked to a component
	*
	* \param instance Lua instance that will interact with the component
	* \param argIndex Index of the component
	*/

	LuaBinding::ComponentBinding* LuaBinding::QueryComponentIndex(Nz::LuaInstance& instance, int argIndex)
	{
		switch (instance.GetType(argIndex))
		{
			case Nz::LuaType_Number:
			{
				ComponentIndex componentIndex = instance.Check<ComponentIndex>(&argIndex);
				if (componentIndex > m_componentBinding.size())
				{
					instance.Error("Invalid component index");
					return nullptr;
				}

				ComponentBinding& binding = m_componentBinding[componentIndex];
				if (binding.name.IsEmpty())
				{
					instance.Error("Invalid component index");
					return nullptr;
				}

				return &binding;
			}

			case Nz::LuaType_String:
			{
				const char* key = instance.CheckString(argIndex);
				auto it = m_componentBindingByName.find(key);
				if (it == m_componentBindingByName.end())
				{
					instance.Error("Invalid component name");
					return nullptr;
				}

				return &m_componentBinding[it->second];
			}
		}

		instance.Error("Invalid component index at #" + Nz::String::Number(argIndex));
		return nullptr;
	}
}
<commit_msg>Sdk/Binding: Fix Entity::Enable default argument<commit_after>// Copyright (C) 2016 Jrme Leclercq, Arnaud Cadot
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp

#include <NDK/LuaBinding.hpp>
#include <NDK/LuaAPI.hpp>

namespace Ndk
{
	/*!
	* \brief Binds SDK module to Lua
	*/

	void LuaBinding::BindSDK()
	{
		/*********************************** Ndk::Application **********************************/

		#ifndef NDK_SERVER
		//application.SetMethod("AddWindow", &Application::AddWindow);
		#endif
		application.BindMethod("AddWorld", [] (Nz::LuaInstance& instance, Application* application) -> int
		{
			instance.Push(application->AddWorld().CreateHandle());
			return 1;
		});

		application.BindMethod("GetUpdateTime", &Application::GetUpdateTime);
		application.BindMethod("Quit", &Application::Quit);

		/*********************************** Ndk::Console **********************************/
		#ifndef NDK_SERVER
		consoleClass.Inherit<Nz::Node>(nodeClass, [] (ConsoleHandle* handle) -> Nz::Node*
		{
			return handle->GetObject();
		});

		consoleClass.BindMethod("AddLine", &Console::AddLine, Nz::Color::White);
		consoleClass.BindMethod("Clear", &Console::Clear);
		consoleClass.BindMethod("GetCharacterSize", &Console::GetCharacterSize);
		consoleClass.BindMethod("GetHistory", &Console::GetHistory);
		consoleClass.BindMethod("GetHistoryBackground", &Console::GetHistoryBackground);
		consoleClass.BindMethod("GetInput", &Console::GetInput);
		consoleClass.BindMethod("GetInputBackground", &Console::GetInputBackground);
		consoleClass.BindMethod("GetSize", &Console::GetSize);
		consoleClass.BindMethod("GetTextFont", &Console::GetTextFont);

		consoleClass.BindMethod("IsVisible", &Console::IsVisible);

		consoleClass.BindMethod("SendCharacter", &Console::SendCharacter);
		//consoleClass.SetMethod("SendEvent", &Console::SendEvent);

		consoleClass.BindMethod("SetCharacterSize", &Console::SetCharacterSize);
		consoleClass.BindMethod("SetSize", &Console::SetSize);
		consoleClass.BindMethod("SetTextFont", &Console::SetTextFont);

		consoleClass.BindMethod("Show", &Console::Show, true);
		#endif

		/*********************************** Ndk::Entity **********************************/
		entityClass.BindMethod("Enable", &Entity::Enable, true);
		entityClass.BindMethod("GetId", &Entity::GetId);
		entityClass.BindMethod("GetWorld", &Entity::GetWorld);
		entityClass.BindMethod("Kill", &Entity::Kill);
		entityClass.BindMethod("IsEnabled", &Entity::IsEnabled);
		entityClass.BindMethod("IsValid", &Entity::IsValid);
		entityClass.BindMethod("RemoveAllComponents", &Entity::RemoveAllComponents);
		entityClass.BindMethod("__tostring", &EntityHandle::ToString);

		entityClass.BindMethod("AddComponent", [this] (Nz::LuaInstance& instance, EntityHandle& handle) -> int
		{
			ComponentBinding* binding = QueryComponentIndex(instance);

			return binding->adder(instance, handle);
		});

		entityClass.BindMethod("GetComponent", [this] (Nz::LuaInstance& instance, EntityHandle& handle) -> int
		{
			ComponentBinding* binding = QueryComponentIndex(instance);

			return binding->getter(instance, handle->GetComponent(binding->index));
		});

		entityClass.BindMethod("RemoveComponent", [this] (Nz::LuaInstance& instance, EntityHandle& handle) -> int
		{
			ComponentBinding* binding = QueryComponentIndex(instance);

			handle->RemoveComponent(binding->index);
			return 0;
		});

		/*********************************** Ndk::NodeComponent **********************************/
		nodeComponent.Inherit<Nz::Node>(nodeClass, [] (NodeComponentHandle* handle) -> Nz::Node*
		{
			return handle->GetObject();
		});

		/*********************************** Ndk::VelocityComponent **********************************/
		velocityComponent.SetGetter([] (Nz::LuaInstance& lua, VelocityComponentHandle& instance)
		{
			std::size_t length;
			const char* member = lua.CheckString(1, &length);

			if (std::strcmp(member, "Linear") == 0)
			{
				lua.Push(instance->linearVelocity);
				return true;
			}

			return false;
		});

		velocityComponent.SetSetter([] (Nz::LuaInstance& lua, VelocityComponentHandle& instance)
		{
			std::size_t length;
			const char* member = lua.CheckString(1, &length);

			int argIndex = 2;
			if (std::strcmp(member, "Linear") == 0)
			{
				instance->linearVelocity = lua.Check<Nz::Vector3f>(&argIndex);
				return true;
			}

			return false;
		});

		/*********************************** Ndk::World **********************************/
		worldClass.BindMethod("CreateEntity", &World::CreateEntity);
		worldClass.BindMethod("CreateEntities", &World::CreateEntities);
		worldClass.BindMethod("Clear", &World::Clear);

		#ifndef NDK_SERVER
		/*********************************** Ndk::GraphicsComponent **********************************/
		graphicsComponent.BindMethod("Attach", &GraphicsComponent::Attach, 0);
		#endif

		// Components functions
		m_componentBinding.resize(BaseComponent::GetMaxComponentIndex());

		BindComponent<NodeComponent>("Node");
		BindComponent<VelocityComponent>("Velocity");

		#ifndef NDK_SERVER
		BindComponent<GraphicsComponent>("Graphics");
		#endif
	}

	/*!
	* \brief Registers the classes that will be used by the Lua instance
	*
	* \param instance Lua instance that will interact with the SDK classes
	*/

	void LuaBinding::RegisterSDK(Nz::LuaInstance& instance)
	{
		// Classes
		application.Register(instance);
		entityClass.Register(instance);
		nodeComponent.Register(instance);
		velocityComponent.Register(instance);
		worldClass.Register(instance);

		#ifndef NDK_SERVER
		consoleClass.Register(instance);
		graphicsComponent.Register(instance);
		#endif

		// Enums

		// ComponentType (fake enumeration to expose component indexes)
		instance.PushTable(0, m_componentBinding.size());
		{
			for (const ComponentBinding& entry : m_componentBinding)
			{
				if (entry.name.IsEmpty())
					continue;

				instance.PushField(entry.name, entry.index);
			}
		}
		instance.SetGlobal("ComponentType");
	}

	/*!
	* \brief Gets the index of the component
	* \return A pointer to the binding linked to a component
	*
	* \param instance Lua instance that will interact with the component
	* \param argIndex Index of the component
	*/

	LuaBinding::ComponentBinding* LuaBinding::QueryComponentIndex(Nz::LuaInstance& instance, int argIndex)
	{
		switch (instance.GetType(argIndex))
		{
			case Nz::LuaType_Number:
			{
				ComponentIndex componentIndex = instance.Check<ComponentIndex>(&argIndex);
				if (componentIndex > m_componentBinding.size())
				{
					instance.Error("Invalid component index");
					return nullptr;
				}

				ComponentBinding& binding = m_componentBinding[componentIndex];
				if (binding.name.IsEmpty())
				{
					instance.Error("Invalid component index");
					return nullptr;
				}

				return &binding;
			}

			case Nz::LuaType_String:
			{
				const char* key = instance.CheckString(argIndex);
				auto it = m_componentBindingByName.find(key);
				if (it == m_componentBindingByName.end())
				{
					instance.Error("Invalid component name");
					return nullptr;
				}

				return &m_componentBinding[it->second];
			}
		}

		instance.Error("Invalid component index at #" + Nz::String::Number(argIndex));
		return nullptr;
	}
}
<|endoftext|>


<commit_before>/*
 Copyright (c) 2001-2004, Kurt Revis.  All rights reserved.

 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 * Neither the name of Kurt Revis, nor Snoize, nor the names of other contributors may be used to endorse or promote products derived from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "MessagePortBroadcaster.h"

#include "MIDISpyShared.h"
#include <pthread.h>

// Private function declarations
CFDataRef LocalMessagePortCallBack(CFMessagePortRef local, SInt32 msgid, CFDataRef data, void *info);
void MessagePortWasInvalidated(CFMessagePortRef messagePort, void *info);
void RemoveRemotePortFromChannelArray(const void *key, const void *value, void *context);

// NOTE This static variable is a dumb workaround. See comment in MessagePortWasInvalidated().
static MessagePortBroadcaster *sOneBroadcaster = NULL;

MessagePortBroadcaster::MessagePortBroadcaster(CFStringRef broadcasterName, MessagePortBroadcasterDelegate *delegate) :
    mDelegate(delegate),
    mBroadcasterName(NULL),
    mLocalPort(NULL),
    mRunLoopSource(NULL),
    mNextListenerIdentifier(0),
    mListenersByIdentifier(NULL),
    mIdentifiersByListener(NULL),
    mListenerArraysByChannel(NULL)
{
    CFMessagePortContext messagePortContext = { 0, (void *)this, NULL, NULL, NULL };

    #if DEBUG
        fprintf(stderr, "MessagePortBroadcaster: creating\n");
    #endif

    sOneBroadcaster = this;

    if (!broadcasterName)
        broadcasterName = CFSTR("Unknown Broadcaster");
    mBroadcasterName = CFStringCreateCopy(kCFAllocatorDefault, broadcasterName);
    if (!mBroadcasterName)
        goto abort;

    // Create a local port for remote listeners to talk to us with
    #if DEBUG
        fprintf(stderr, "MessagePortBroadcaster: creating local port\n");
    #endif
    mLocalPort = CFMessagePortCreateLocal(kCFAllocatorDefault, mBroadcasterName, LocalMessagePortCallBack, &messagePortContext, FALSE);
    if (!mLocalPort) {
        #if DEBUG
            fprintf(stderr, "MessagePortBroadcaster: couldn't create local port!\n");
        #endif
        goto abort;
    }

    // And add it to the current run loop
    mRunLoopSource = CFMessagePortCreateRunLoopSource(kCFAllocatorDefault, mLocalPort, 0);
    if (!mRunLoopSource) {
        #if DEBUG
            fprintf(stderr, "MessagePortBroadcaster: couldn't create run loop source for local port!\n");
        #endif
        goto abort;
    }
    CFRunLoopAddSource(CFRunLoopGetCurrent(), mRunLoopSource, kCFRunLoopDefaultMode);

    // Create structures to keep track of our listeners
    mListenersByIdentifier = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
    mIdentifiersByListener = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL);
    mListenerArraysByChannel = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
    if (!mListenersByIdentifier || !mIdentifiersByListener || !mListenerArraysByChannel) {
        #if DEBUG
            fprintf(stderr, "MessagePortBroadcaster: couldn't create a listener dictionary!\n");
        #endif
        goto abort;
    }

    pthread_mutex_init(&mListenerStructuresMutex, NULL);

    return;

abort:
    if (mListenerArraysByChannel)
        CFRelease(mListenerArraysByChannel);

    if (mIdentifiersByListener)
        CFRelease(mIdentifiersByListener);

    if (mListenersByIdentifier)
        CFRelease(mListenersByIdentifier);

    if (mRunLoopSource) {
        CFRunLoopSourceInvalidate(mRunLoopSource);
        CFRelease(mRunLoopSource);
    }

    if (mLocalPort) {
        CFMessagePortInvalidate(mLocalPort);
        CFRelease(mLocalPort);
    }

    if (mBroadcasterName)
        CFRelease(mBroadcasterName);

    throw MessagePortBroadcasterException();
}

MessagePortBroadcaster::~MessagePortBroadcaster()
{
    #if DEBUG
        fprintf(stderr, "MessagePortBroadcaster: destroying\n");
    #endif

    // As we delete our dictionaries, any leftover remote CFMessagePorts will get invalidated.
    // But we want to bypass the usual invalidation code (since we're just taking everything
    // down anyway), so we set sOneBroadcaster to NULL. MessagePortWasInvalidated() will
    // still get called, but it won't be able to call back into this C++ object.
    // NOTE When restructuring to get rid of sOneBroadcaster, you'll need to rethink this.
    sOneBroadcaster = NULL;

    pthread_mutex_destroy(&mListenerStructuresMutex);

    if (mListenerArraysByChannel)
        CFRelease(mListenerArraysByChannel);

    if (mIdentifiersByListener)
        CFRelease(mIdentifiersByListener);

    if (mListenersByIdentifier)
        CFRelease(mListenersByIdentifier);

    if (mRunLoopSource) {
        CFRunLoopSourceInvalidate(mRunLoopSource);
        CFRelease(mRunLoopSource);
    }

    if (mLocalPort) {
        CFMessagePortInvalidate(mLocalPort);
        CFRelease(mLocalPort);
    }

    if (mBroadcasterName)
        CFRelease(mBroadcasterName);
}

void MessagePortBroadcaster::Broadcast(CFDataRef data, SInt32 channel)
{
    CFArrayRef listeners;
    CFIndex listenerIndex;

    #if DEBUG && 0
        fprintf(stderr, "MessagePortBroadcaster: broadcast(%p, %p)\n", data, (void *)channel);
    #endif

    pthread_mutex_lock(&mListenerStructuresMutex);

    listeners = (CFArrayRef)CFDictionaryGetValue(mListenerArraysByChannel, (void *)channel);
    if (listeners) {
        listenerIndex = CFArrayGetCount(listeners);

        while (listenerIndex--) {
            CFMessagePortRef listenerPort = (CFMessagePortRef)CFArrayGetValueAtIndex(listeners, listenerIndex);
            CFMessagePortSendRequest(listenerPort, 0, data, 300, 0, NULL, NULL);
        }
    }

    pthread_mutex_unlock(&mListenerStructuresMutex);
}

//
// Private functions and methods
//

CFDataRef LocalMessagePortCallBack(CFMessagePortRef local, SInt32 msgid, CFDataRef data, void *info)
{
    MessagePortBroadcaster *broadcaster = (MessagePortBroadcaster *)info;
    CFDataRef result = NULL;

    #if DEBUG && 0
        fprintf(stderr, "MessagePortBroadcaster: message port callback(msgid=%ld)\n", msgid);
    #endif

    switch (msgid) {
        case kSpyingMIDIDriverGetNextListenerIdentifierMessageID:
            result = broadcaster->NextListenerIdentifier();
            break;

        case kSpyingMIDIDriverAddListenerMessageID:
            broadcaster->AddListener(data);
            break;

        case kSpyingMIDIDriverConnectDestinationMessageID:
            broadcaster->ChangeListenerChannelStatus(data, true);
            break;

        case kSpyingMIDIDriverDisconnectDestinationMessageID:
            broadcaster->ChangeListenerChannelStatus(data, false);
            break;

        default:
            break;
    }

    return result;
}

CFDataRef	MessagePortBroadcaster::NextListenerIdentifier()
{
    // Client is starting up; it wants to know what identifier to use (so it can name its local port).
    // We give it that data in a reply.

    CFDataRef returnedData;

    mNextListenerIdentifier++;
    returnedData = CFDataCreate(kCFAllocatorDefault, (UInt8 *)&mNextListenerIdentifier, sizeof(UInt32));

    return returnedData;
}

void	MessagePortBroadcaster::AddListener(CFDataRef listenerIdentifierData)
{
    // The listener has created a local port on its side, and we need to create a remote port for it.
    // No reply is necessary.

    const UInt8 *dataBytes;
    UInt32 listenerIdentifier;
    CFStringRef listenerPortName;
    CFMessagePortRef remotePort;

    if (!listenerIdentifierData || CFDataGetLength(listenerIdentifierData) != sizeof(UInt32))
        return;

    dataBytes = CFDataGetBytePtr(listenerIdentifierData);
    if (!dataBytes)
        return;

    listenerIdentifier = *(const UInt32 *)dataBytes;
    listenerPortName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@-%lu"), mBroadcasterName, listenerIdentifier);

    remotePort = CFMessagePortCreateRemote(kCFAllocatorDefault, listenerPortName);
    if (remotePort) {
        CFMessagePortSetInvalidationCallBack(remotePort, MessagePortWasInvalidated);

        pthread_mutex_lock(&mListenerStructuresMutex);
        CFDictionarySetValue(mListenersByIdentifier, (void *)listenerIdentifier, (void *)remotePort);
        CFDictionarySetValue(mIdentifiersByListener, (void *)remotePort, (void *)listenerIdentifier);
        pthread_mutex_unlock(&mListenerStructuresMutex);

        CFRelease(remotePort);

        // TODO we don't really want to do this here -- we want to do it when the client adds a channel
        if (mDelegate && CFDictionaryGetCount(mListenersByIdentifier) == 1)
            mDelegate->BroadcasterListenerCountChanged(this, true);
    }

    CFRelease(listenerPortName);
}

void	MessagePortBroadcaster::ChangeListenerChannelStatus(CFDataRef messageData, Boolean shouldAdd)
{
    // From the message data given, take out the identifier of the listener, and the channel it is concerned with.
    // Then find the remote message port corresponding to that identifier.
    // Then find the array of listeners for this channel (creating it if necessary), and add/remove the remote port from the array.
    // No reply is necessary.

    const UInt8 *dataBytes;
    UInt32 identifier;
    SInt32 channel;
    CFMessagePortRef remotePort;
    CFMutableArrayRef channelListeners;

    if (!messageData || CFDataGetLength(messageData) != sizeof(UInt32) + sizeof(SInt32))
        return;
    dataBytes = CFDataGetBytePtr(messageData);
    if (!dataBytes)
        return;
    identifier = *(UInt32 *)dataBytes;
    channel = *(SInt32 *)(dataBytes + sizeof(UInt32));

    remotePort = (CFMessagePortRef)CFDictionaryGetValue(mListenersByIdentifier, (void *)identifier);
    if (!remotePort)
        return;

    pthread_mutex_lock(&mListenerStructuresMutex);

    channelListeners = (CFMutableArrayRef)CFDictionaryGetValue(mListenerArraysByChannel, (void *)channel);
    if (!channelListeners && shouldAdd) {
        channelListeners = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
        CFDictionarySetValue(mListenerArraysByChannel, (void *)channel, channelListeners);
    }

    if (shouldAdd) {
        CFArrayAppendValue(channelListeners, remotePort);
    } else if (channelListeners) {
        CFIndex index;

        index = CFArrayGetFirstIndexOfValue(channelListeners, CFRangeMake(0, CFArrayGetCount(channelListeners)), remotePort);
        if (index != kCFNotFound)
            CFArrayRemoveValueAtIndex(channelListeners, index);
    }

    pthread_mutex_unlock(&mListenerStructuresMutex);
}

void MessagePortWasInvalidated(CFMessagePortRef messagePort, void *info)
{
    // NOTE: The info pointer provided to this function is useless. CFMessagePort provides no way to set it for remote ports.
    // Thus, we have to assume we have one MessagePortBroadcaster, which we look up statically. Lame!
    // TODO come up with a better solution to this

    #if DEBUG && 0
        fprintf(stderr, "MessagePortBroadcaster: remote port was invalidated\n");
    #endif

    if (sOneBroadcaster)
        sOneBroadcaster->RemoveListenerWithRemotePort(messagePort);
}

void	MessagePortBroadcaster::RemoveListenerWithRemotePort(CFMessagePortRef remotePort)
{
    UInt32 identifier;

    pthread_mutex_lock(&mListenerStructuresMutex);

    // Remove this listener from our dictionaries
    const void* ptrId = CFDictionaryGetValue(mIdentifiersByListener, (void *)remotePort);
#if __LP64__
    identifier = (uintptr_t)ptrId & 0xFFFFFFFFUL;
#else
    identifier = (UInt32)ptrId;
#endif
    CFDictionaryRemoveValue(mListenersByIdentifier, (void *)identifier);
    CFDictionaryRemoveValue(mIdentifiersByListener, (void *)remotePort);

    // Also go through the listener array for each channel and remove remotePort from there too
    CFDictionaryApplyFunction(mListenerArraysByChannel, RemoveRemotePortFromChannelArray, remotePort);

    pthread_mutex_unlock(&mListenerStructuresMutex);

    // TODO we don't really want to do this here -- we want to do it when a client removes a channel
    if (mDelegate && CFDictionaryGetCount(mListenersByIdentifier) == 0)
        mDelegate->BroadcasterListenerCountChanged(this, false);
}

void RemoveRemotePortFromChannelArray(const void *key, const void *value, void *context)
{
    // We don't care about the key (it's a channel number)
    CFMutableArrayRef listenerArray = (CFMutableArrayRef)value;
    CFMessagePortRef remotePort = (CFMessagePortRef)context;
    CFIndex index;

    index = CFArrayGetFirstIndexOfValue(listenerArray, CFRangeMake(0, CFArrayGetCount(listenerArray)), remotePort);
    if (index != kCFNotFound)
        CFArrayRemoveValueAtIndex(listenerArray, index);
}
<commit_msg>Fix a potential leak (caught by the analyzer)<commit_after>/*
 Copyright (c) 2001-2004, Kurt Revis.  All rights reserved.

 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 * Neither the name of Kurt Revis, nor Snoize, nor the names of other contributors may be used to endorse or promote products derived from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "MessagePortBroadcaster.h"

#include "MIDISpyShared.h"
#include <pthread.h>

// Private function declarations
CFDataRef LocalMessagePortCallBack(CFMessagePortRef local, SInt32 msgid, CFDataRef data, void *info);
void MessagePortWasInvalidated(CFMessagePortRef messagePort, void *info);
void RemoveRemotePortFromChannelArray(const void *key, const void *value, void *context);

// NOTE This static variable is a dumb workaround. See comment in MessagePortWasInvalidated().
static MessagePortBroadcaster *sOneBroadcaster = NULL;

MessagePortBroadcaster::MessagePortBroadcaster(CFStringRef broadcasterName, MessagePortBroadcasterDelegate *delegate) :
    mDelegate(delegate),
    mBroadcasterName(NULL),
    mLocalPort(NULL),
    mRunLoopSource(NULL),
    mNextListenerIdentifier(0),
    mListenersByIdentifier(NULL),
    mIdentifiersByListener(NULL),
    mListenerArraysByChannel(NULL)
{
    CFMessagePortContext messagePortContext = { 0, (void *)this, NULL, NULL, NULL };

    #if DEBUG
        fprintf(stderr, "MessagePortBroadcaster: creating\n");
    #endif

    sOneBroadcaster = this;

    if (!broadcasterName)
        broadcasterName = CFSTR("Unknown Broadcaster");
    mBroadcasterName = CFStringCreateCopy(kCFAllocatorDefault, broadcasterName);
    if (!mBroadcasterName)
        goto abort;

    // Create a local port for remote listeners to talk to us with
    #if DEBUG
        fprintf(stderr, "MessagePortBroadcaster: creating local port\n");
    #endif
    mLocalPort = CFMessagePortCreateLocal(kCFAllocatorDefault, mBroadcasterName, LocalMessagePortCallBack, &messagePortContext, FALSE);
    if (!mLocalPort) {
        #if DEBUG
            fprintf(stderr, "MessagePortBroadcaster: couldn't create local port!\n");
        #endif
        goto abort;
    }

    // And add it to the current run loop
    mRunLoopSource = CFMessagePortCreateRunLoopSource(kCFAllocatorDefault, mLocalPort, 0);
    if (!mRunLoopSource) {
        #if DEBUG
            fprintf(stderr, "MessagePortBroadcaster: couldn't create run loop source for local port!\n");
        #endif
        goto abort;
    }
    CFRunLoopAddSource(CFRunLoopGetCurrent(), mRunLoopSource, kCFRunLoopDefaultMode);

    // Create structures to keep track of our listeners
    mListenersByIdentifier = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
    mIdentifiersByListener = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL);
    mListenerArraysByChannel = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
    if (!mListenersByIdentifier || !mIdentifiersByListener || !mListenerArraysByChannel) {
        #if DEBUG
            fprintf(stderr, "MessagePortBroadcaster: couldn't create a listener dictionary!\n");
        #endif
        goto abort;
    }

    pthread_mutex_init(&mListenerStructuresMutex, NULL);

    return;

abort:
    if (mListenerArraysByChannel)
        CFRelease(mListenerArraysByChannel);

    if (mIdentifiersByListener)
        CFRelease(mIdentifiersByListener);

    if (mListenersByIdentifier)
        CFRelease(mListenersByIdentifier);

    if (mRunLoopSource) {
        CFRunLoopSourceInvalidate(mRunLoopSource);
        CFRelease(mRunLoopSource);
    }

    if (mLocalPort) {
        CFMessagePortInvalidate(mLocalPort);
        CFRelease(mLocalPort);
    }

    if (mBroadcasterName)
        CFRelease(mBroadcasterName);

    throw MessagePortBroadcasterException();
}

MessagePortBroadcaster::~MessagePortBroadcaster()
{
    #if DEBUG
        fprintf(stderr, "MessagePortBroadcaster: destroying\n");
    #endif

    // As we delete our dictionaries, any leftover remote CFMessagePorts will get invalidated.
    // But we want to bypass the usual invalidation code (since we're just taking everything
    // down anyway), so we set sOneBroadcaster to NULL. MessagePortWasInvalidated() will
    // still get called, but it won't be able to call back into this C++ object.
    // NOTE When restructuring to get rid of sOneBroadcaster, you'll need to rethink this.
    sOneBroadcaster = NULL;

    pthread_mutex_destroy(&mListenerStructuresMutex);

    if (mListenerArraysByChannel)
        CFRelease(mListenerArraysByChannel);

    if (mIdentifiersByListener)
        CFRelease(mIdentifiersByListener);

    if (mListenersByIdentifier)
        CFRelease(mListenersByIdentifier);

    if (mRunLoopSource) {
        CFRunLoopSourceInvalidate(mRunLoopSource);
        CFRelease(mRunLoopSource);
    }

    if (mLocalPort) {
        CFMessagePortInvalidate(mLocalPort);
        CFRelease(mLocalPort);
    }

    if (mBroadcasterName)
        CFRelease(mBroadcasterName);
}

void MessagePortBroadcaster::Broadcast(CFDataRef data, SInt32 channel)
{
    CFArrayRef listeners;
    CFIndex listenerIndex;

    #if DEBUG && 0
        fprintf(stderr, "MessagePortBroadcaster: broadcast(%p, %p)\n", data, (void *)channel);
    #endif

    pthread_mutex_lock(&mListenerStructuresMutex);

    listeners = (CFArrayRef)CFDictionaryGetValue(mListenerArraysByChannel, (void *)channel);
    if (listeners) {
        listenerIndex = CFArrayGetCount(listeners);

        while (listenerIndex--) {
            CFMessagePortRef listenerPort = (CFMessagePortRef)CFArrayGetValueAtIndex(listeners, listenerIndex);
            CFMessagePortSendRequest(listenerPort, 0, data, 300, 0, NULL, NULL);
        }
    }

    pthread_mutex_unlock(&mListenerStructuresMutex);
}

//
// Private functions and methods
//

CFDataRef LocalMessagePortCallBack(CFMessagePortRef local, SInt32 msgid, CFDataRef data, void *info)
{
    MessagePortBroadcaster *broadcaster = (MessagePortBroadcaster *)info;
    CFDataRef result = NULL;

    #if DEBUG && 0
        fprintf(stderr, "MessagePortBroadcaster: message port callback(msgid=%ld)\n", msgid);
    #endif

    switch (msgid) {
        case kSpyingMIDIDriverGetNextListenerIdentifierMessageID:
            result = broadcaster->NextListenerIdentifier();
            break;

        case kSpyingMIDIDriverAddListenerMessageID:
            broadcaster->AddListener(data);
            break;

        case kSpyingMIDIDriverConnectDestinationMessageID:
            broadcaster->ChangeListenerChannelStatus(data, true);
            break;

        case kSpyingMIDIDriverDisconnectDestinationMessageID:
            broadcaster->ChangeListenerChannelStatus(data, false);
            break;

        default:
            break;
    }

    return result;
}

CFDataRef	MessagePortBroadcaster::NextListenerIdentifier()
{
    // Client is starting up; it wants to know what identifier to use (so it can name its local port).
    // We give it that data in a reply.

    CFDataRef returnedData;

    mNextListenerIdentifier++;
    returnedData = CFDataCreate(kCFAllocatorDefault, (UInt8 *)&mNextListenerIdentifier, sizeof(UInt32));

    return returnedData;
}

void	MessagePortBroadcaster::AddListener(CFDataRef listenerIdentifierData)
{
    // The listener has created a local port on its side, and we need to create a remote port for it.
    // No reply is necessary.

    const UInt8 *dataBytes;
    UInt32 listenerIdentifier;
    CFStringRef listenerPortName;
    CFMessagePortRef remotePort;

    if (!listenerIdentifierData || CFDataGetLength(listenerIdentifierData) != sizeof(UInt32))
        return;

    dataBytes = CFDataGetBytePtr(listenerIdentifierData);
    if (!dataBytes)
        return;

    listenerIdentifier = *(const UInt32 *)dataBytes;
    listenerPortName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@-%lu"), mBroadcasterName, listenerIdentifier);

    remotePort = CFMessagePortCreateRemote(kCFAllocatorDefault, listenerPortName);
    if (remotePort) {
        CFMessagePortSetInvalidationCallBack(remotePort, MessagePortWasInvalidated);

        pthread_mutex_lock(&mListenerStructuresMutex);
        CFDictionarySetValue(mListenersByIdentifier, (void *)listenerIdentifier, (void *)remotePort);
        CFDictionarySetValue(mIdentifiersByListener, (void *)remotePort, (void *)listenerIdentifier);
        pthread_mutex_unlock(&mListenerStructuresMutex);

        CFRelease(remotePort);

        // TODO we don't really want to do this here -- we want to do it when the client adds a channel
        if (mDelegate && CFDictionaryGetCount(mListenersByIdentifier) == 1)
            mDelegate->BroadcasterListenerCountChanged(this, true);
    }

    CFRelease(listenerPortName);
}

void	MessagePortBroadcaster::ChangeListenerChannelStatus(CFDataRef messageData, Boolean shouldAdd)
{
    // From the message data given, take out the identifier of the listener, and the channel it is concerned with.
    // Then find the remote message port corresponding to that identifier.
    // Then find the array of listeners for this channel (creating it if necessary), and add/remove the remote port from the array.
    // No reply is necessary.

    const UInt8 *dataBytes;
    UInt32 identifier;
    SInt32 channel;
    CFMessagePortRef remotePort;
    CFMutableArrayRef channelListeners;

    if (!messageData || CFDataGetLength(messageData) != sizeof(UInt32) + sizeof(SInt32))
        return;
    dataBytes = CFDataGetBytePtr(messageData);
    if (!dataBytes)
        return;
    identifier = *(UInt32 *)dataBytes;
    channel = *(SInt32 *)(dataBytes + sizeof(UInt32));

    remotePort = (CFMessagePortRef)CFDictionaryGetValue(mListenersByIdentifier, (void *)identifier);
    if (!remotePort)
        return;

    pthread_mutex_lock(&mListenerStructuresMutex);

    channelListeners = (CFMutableArrayRef)CFDictionaryGetValue(mListenerArraysByChannel, (void *)channel);
    if (!channelListeners && shouldAdd) {
        channelListeners = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
        if (channelListeners) {
            CFDictionarySetValue(mListenerArraysByChannel, (void *)channel, channelListeners);
            CFRelease(channelListeners);
        }
    }

    if (shouldAdd) {
        CFArrayAppendValue(channelListeners, remotePort);
    } else if (channelListeners) {
        CFIndex index;

        index = CFArrayGetFirstIndexOfValue(channelListeners, CFRangeMake(0, CFArrayGetCount(channelListeners)), remotePort);
        if (index != kCFNotFound)
            CFArrayRemoveValueAtIndex(channelListeners, index);
    }

    pthread_mutex_unlock(&mListenerStructuresMutex);
}

void MessagePortWasInvalidated(CFMessagePortRef messagePort, void *info)
{
    // NOTE: The info pointer provided to this function is useless. CFMessagePort provides no way to set it for remote ports.
    // Thus, we have to assume we have one MessagePortBroadcaster, which we look up statically. Lame!
    // TODO come up with a better solution to this

    #if DEBUG && 0
        fprintf(stderr, "MessagePortBroadcaster: remote port was invalidated\n");
    #endif

    if (sOneBroadcaster)
        sOneBroadcaster->RemoveListenerWithRemotePort(messagePort);
}

void	MessagePortBroadcaster::RemoveListenerWithRemotePort(CFMessagePortRef remotePort)
{
    UInt32 identifier;

    pthread_mutex_lock(&mListenerStructuresMutex);

    // Remove this listener from our dictionaries
    const void* ptrId = CFDictionaryGetValue(mIdentifiersByListener, (void *)remotePort);
#if __LP64__
    identifier = (uintptr_t)ptrId & 0xFFFFFFFFUL;
#else
    identifier = (UInt32)ptrId;
#endif
    CFDictionaryRemoveValue(mListenersByIdentifier, (void *)identifier);
    CFDictionaryRemoveValue(mIdentifiersByListener, (void *)remotePort);

    // Also go through the listener array for each channel and remove remotePort from there too
    CFDictionaryApplyFunction(mListenerArraysByChannel, RemoveRemotePortFromChannelArray, remotePort);

    pthread_mutex_unlock(&mListenerStructuresMutex);

    // TODO we don't really want to do this here -- we want to do it when a client removes a channel
    if (mDelegate && CFDictionaryGetCount(mListenersByIdentifier) == 0)
        mDelegate->BroadcasterListenerCountChanged(this, false);
}

void RemoveRemotePortFromChannelArray(const void *key, const void *value, void *context)
{
    // We don't care about the key (it's a channel number)
    CFMutableArrayRef listenerArray = (CFMutableArrayRef)value;
    CFMessagePortRef remotePort = (CFMessagePortRef)context;
    CFIndex index;

    index = CFArrayGetFirstIndexOfValue(listenerArray, CFRangeMake(0, CFArrayGetCount(listenerArray)), remotePort);
    if (index != kCFNotFound)
        CFArrayRemoveValueAtIndex(listenerArray, index);
}
<|endoftext|>