<commit_before>#include "Runtime/Collision/CCollisionResponseData.hpp"

#include <array>

#include "Runtime/CRandom16.hpp"
#include "Runtime/CSimplePool.hpp"
#include "Runtime/Graphics/CModel.hpp"
#include "Runtime/Particle/CDecalDescription.hpp"
#include "Runtime/Particle/CElectricDescription.hpp"
#include "Runtime/Particle/CGenDescription.hpp"
#include "Runtime/Particle/CParticleDataFactory.hpp"
#include "Runtime/Particle/CSwooshDescription.hpp"

namespace urde {
namespace {
constexpr std::array skWorldMaterialTable{
    EWeaponCollisionResponseTypes::Default, EWeaponCollisionResponseTypes::Unknown2,
    EWeaponCollisionResponseTypes::Metal,   EWeaponCollisionResponseTypes::Grass,
    EWeaponCollisionResponseTypes::Ice,     EWeaponCollisionResponseTypes::Goo,
    EWeaponCollisionResponseTypes::Metal,   EWeaponCollisionResponseTypes::Wood,
    EWeaponCollisionResponseTypes::Grass,   EWeaponCollisionResponseTypes::Lava,
    EWeaponCollisionResponseTypes::Lava,    EWeaponCollisionResponseTypes::Ice,
    EWeaponCollisionResponseTypes::Mud,     EWeaponCollisionResponseTypes::Metal,
    EWeaponCollisionResponseTypes::Default, EWeaponCollisionResponseTypes::Goo,
    EWeaponCollisionResponseTypes::Goo,     EWeaponCollisionResponseTypes::Sand,
    EWeaponCollisionResponseTypes::Default, EWeaponCollisionResponseTypes::Default,
    EWeaponCollisionResponseTypes::Default, EWeaponCollisionResponseTypes::Metal,
    EWeaponCollisionResponseTypes::Default, EWeaponCollisionResponseTypes::Default,
    EWeaponCollisionResponseTypes::Default, EWeaponCollisionResponseTypes::Default,
    EWeaponCollisionResponseTypes::Default, EWeaponCollisionResponseTypes::Default,
    EWeaponCollisionResponseTypes::Default, EWeaponCollisionResponseTypes::Default,
    EWeaponCollisionResponseTypes::Default, EWeaponCollisionResponseTypes::Default,
};

constexpr s32 kInvalidSFX = -1;

constexpr std::array<FourCC, 94> kWCRTSFXIDs{{
    SBIG('NSFX'), SBIG('DSFX'), SBIG('CSFX'), SBIG('MSFX'), SBIG('GRFX'), SBIG('ICFX'), SBIG('GOFX'), SBIG('WSFX'),
    SBIG('WTFX'), SBIG('2MUD'), SBIG('2LAV'), SBIG('2SAN'), SBIG('2PRJ'), SBIG('DCFX'), SBIG('DSFX'), SBIG('DSHX'),
    SBIG('DEFX'), SBIG('ESFX'), SBIG('SHFX'), SBIG('BEFX'), SBIG('WWFX'), SBIG('TAFX'), SBIG('GTFX'), SBIG('SPFX'),
    SBIG('FPFX'), SBIG('FFFX'), SBIG('PAFX'), SBIG('BMFX'), SBIG('BFFX'), SBIG('PBFX'), SBIG('IBFX'), SBIG('4SVA'),
    SBIG('4RPR'), SBIG('4MTR'), SBIG('4PDS'), SBIG('4FLB'), SBIG('4DRN'), SBIG('4MRE'), SBIG('CZFX'), SBIG('JZAS'),
    SBIG('2ISE'), SBIG('2BSE'), SBIG('2ATB'), SBIG('2ATA'), SBIG('BSFX'), SBIG('WSFX'), SBIG('TSFX'), SBIG('GSFX'),
    SBIG('SSFX'), SBIG('FSFX'), SBIG('SFFX'), SBIG('PSFX'), SBIG('MSFX'), SBIG('SBFX'), SBIG('PBSX'), SBIG('IBSX'),
    SBIG('5SVA'), SBIG('5RPR'), SBIG('5MTR'), SBIG('5PDS'), SBIG('5FLB'), SBIG('5DRN'), SBIG('5MRE'), SBIG('CSFX'),
    SBIG('JZPS'), SBIG('4ISE'), SBIG('4BSE'), SBIG('4ATB'), SBIG('4ATA'), SBIG('BHFX'), SBIG('WHFX'), SBIG('THFX'),
    SBIG('GHFX'), SBIG('SHFX'), SBIG('FHFX'), SBIG('HFFX'), SBIG('PHFX'), SBIG('MHFX'), SBIG('HBFX'), SBIG('PBHX'),
    SBIG('IBHX'), SBIG('6SVA'), SBIG('6RPR'), SBIG('6MTR'), SBIG('6PDS'), SBIG('6FLB'), SBIG('6DRN'), SBIG('6MRE'),
    SBIG('CHFX'), SBIG('JZHS'), SBIG('6ISE'), SBIG('6BSE'), SBIG('6ATB'), SBIG('6ATA'),
}};

constexpr std::array<FourCC, 94> kWCRTIDs{{
    SBIG('NODP'), SBIG('DEFS'), SBIG('CRTS'), SBIG('MTLS'), SBIG('GRAS'), SBIG('ICEE'), SBIG('GOOO'), SBIG('WODS'),
    SBIG('WATR'), SBIG('1MUD'), SBIG('1LAV'), SBIG('1SAN'), SBIG('1PRJ'), SBIG('DCHR'), SBIG('DCHS'), SBIG('DCSH'),
    SBIG('DENM'), SBIG('DESP'), SBIG('DESH'), SBIG('BTLE'), SBIG('WASP'), SBIG('TALP'), SBIG('PTGM'), SBIG('SPIR'),
    SBIG('FPIR'), SBIG('FFLE'), SBIG('PARA'), SBIG('BMON'), SBIG('BFLR'), SBIG('PBOS'), SBIG('IBOS'), SBIG('1SVA'),
    SBIG('1RPR'), SBIG('1MTR'), SBIG('1PDS'), SBIG('1FLB'), SBIG('1DRN'), SBIG('1MRE'), SBIG('CHOZ'), SBIG('JZAP'),
    SBIG('1ISE'), SBIG('1BSE'), SBIG('1ATB'), SBIG('1ATA'), SBIG('BTSP'), SBIG('WWSP'), SBIG('TASP'), SBIG('TGSP'),
    SBIG('SPSP'), SBIG('FPSP'), SBIG('FFSP'), SBIG('PSSP'), SBIG('BMSP'), SBIG('BFSP'), SBIG('PBSP'), SBIG('IBSP'),
    SBIG('2SVA'), SBIG('2RPR'), SBIG('2MTR'), SBIG('2PDS'), SBIG('2FLB'), SBIG('2DRN'), SBIG('2MRE'), SBIG('CHSP'),
    SBIG('JZSP'), SBIG('3ISE'), SBIG('3BSE'), SBIG('3ATB'), SBIG('3ATA'), SBIG('BTSH'), SBIG('WWSH'), SBIG('TASH'),
    SBIG('TGSH'), SBIG('SPSH'), SBIG('FPSH'), SBIG('FFSH'), SBIG('PSSH'), SBIG('BMSH'), SBIG('BFSH'), SBIG('PBSH'),
    SBIG('IBSH'), SBIG('3SVA'), SBIG('3RPR'), SBIG('3MTR'), SBIG('3PDS'), SBIG('3FLB'), SBIG('3DRN'), SBIG('3MRE'),
    SBIG('CHSH'), SBIG('JZSH'), SBIG('5ISE'), SBIG('5BSE'), SBIG('5ATB'), SBIG('5ATA'),
}};

constexpr std::array<FourCC, 14> kWCRTDecalIDs{{
    SBIG('NCDL'),
    SBIG('DDCL'),
    SBIG('CODL'),
    SBIG('MEDL'),
    SBIG('GRDL'),
    SBIG('ICDL'),
    SBIG('GODL'),
    SBIG('WODL'),
    SBIG('WTDL'),
    SBIG('3MUD'),
    SBIG('3LAV'),
    SBIG('3SAN'),
    SBIG('CHDL'),
    SBIG('ENDL'),
}};

using CPF = CParticleDataFactory;
} // Anonymous namespace

void CCollisionResponseData::AddParticleSystemToResponse(EWeaponCollisionResponseTypes type, CInputStream& in,
                                                         CSimplePool* resPool) {
  const auto i = size_t(type);
  const std::vector<CAssetId> tracker(8);
  x0_generators[i].emplace(CPF::GetChildGeneratorDesc(in, resPool, tracker).m_token);
}

bool CCollisionResponseData::CheckAndAddDecalToResponse(FourCC clsId, CInputStream& in, CSimplePool* resPool) {
  size_t i = 0;
  for (const FourCC& type : kWCRTDecalIDs) {
    if (type == clsId) {
      const FourCC cls = CPF::GetClassID(in);
      if (cls == SBIG('NONE')) {
        return true;
      }

      const CAssetId id{u64(in.readUint32Big())};
      if (!id.IsValid()) {
        return true;
      }

      x20_decals[i].emplace(resPool->GetObj({FOURCC('DPSC'), id}));
      return true;
    }
    i++;
  }
  return false;
}

bool CCollisionResponseData::CheckAndAddSoundFXToResponse(FourCC clsId, CInputStream& in) {
  size_t i = 0;
  for (const FourCC& type : kWCRTSFXIDs) {
    if (type == clsId) {
      const FourCC cls = CPF::GetClassID(in);
      if (cls == SBIG('NONE')) {
        return true;
      }

      x10_sfx[i] = CPF::GetInt(in);
      return true;
    }
    i++;
  }

  return false;
}

bool CCollisionResponseData::CheckAndAddParticleSystemToResponse(FourCC clsId, CInputStream& in, CSimplePool* resPool) {
  size_t i = 0;
  for (const FourCC& type : kWCRTIDs) {
    if (type == clsId) {
      AddParticleSystemToResponse(EWeaponCollisionResponseTypes(i), in, resPool);
      return true;
    }
    i++;
  }
  return false;
}

bool CCollisionResponseData::CheckAndAddResourceToResponse(FourCC clsId, CInputStream& in, CSimplePool* resPool) {
  if (CheckAndAddParticleSystemToResponse(clsId, in, resPool))
    return true;
  if (CheckAndAddSoundFXToResponse(clsId, in))
    return true;
  if (CheckAndAddDecalToResponse(clsId, in, resPool))
    return true;

  return false;
}

CCollisionResponseData::CCollisionResponseData(CInputStream& in, CSimplePool* resPool)
: x30_RNGE(50.f), x34_FOFF(0.2f) {
  x0_generators.resize(94);
  x10_sfx.resize(94);
  x20_decals.resize(94);
  for (s32& id : x10_sfx)
    id = kInvalidSFX;

  FourCC clsId = CPF::GetClassID(in);
  if (clsId == UncookedResType()) {
    CRandom16 rand;
    CGlobalRandom gr(rand);

    while (clsId != SBIG('_END')) {
      clsId = CPF::GetClassID(in);
      if (CheckAndAddResourceToResponse(clsId, in, resPool))
        continue;

      if (clsId == SBIG('RNGE')) {
        CPF::GetClassID(in);
        x30_RNGE = CPF::GetReal(in);
      } else if (clsId == SBIG('FOFF')) {
        CPF::GetClassID(in);
        x34_FOFF = CPF::GetReal(in);
      }
    }
  }
}

const std::optional<TLockedToken<CGenDescription>>&
CCollisionResponseData::GetParticleDescription(EWeaponCollisionResponseTypes type) const {
  if (x0_generators[size_t(type)]) {
    return x0_generators[size_t(type)];
  }

  bool foundType = false;
  if (ResponseTypeIsEnemyNormal(type)) {
    type = EWeaponCollisionResponseTypes::EnemyNormal;
    foundType = true;
  } else if (ResponseTypeIsEnemySpecial(type)) {
    type = EWeaponCollisionResponseTypes::EnemySpecial;
    foundType = true;
  } else if (ResponseTypeIsEnemyShielded(type)) {
    type = EWeaponCollisionResponseTypes::EnemyShielded;
    foundType = true;
  }

  if (foundType && !x0_generators[size_t(type)]) {
    type = EWeaponCollisionResponseTypes::EnemyNormal;
  }

  if (!x0_generators[size_t(type)] && type != EWeaponCollisionResponseTypes::None) {
    type = EWeaponCollisionResponseTypes::Default;
  }

  return x0_generators[size_t(type)];
}

const std::optional<TLockedToken<CDecalDescription>>&
CCollisionResponseData::GetDecalDescription(EWeaponCollisionResponseTypes type) const {
  return x20_decals[size_t(type)];
}

s32 CCollisionResponseData::GetSoundEffectId(EWeaponCollisionResponseTypes type) const {
  if (x10_sfx[size_t(type)] == kInvalidSFX) {
    if (ResponseTypeIsEnemyNormal(type))
      type = EWeaponCollisionResponseTypes::EnemyNormal;
    else if (ResponseTypeIsEnemySpecial(type))
      type = EWeaponCollisionResponseTypes::EnemySpecial;
    else if (ResponseTypeIsEnemyShielded(type))
      type = EWeaponCollisionResponseTypes::EnemyShielded;
    else
      type = EWeaponCollisionResponseTypes::Default;
  }

  return x10_sfx[size_t(type)];
}

EWeaponCollisionResponseTypes CCollisionResponseData::GetWorldCollisionResponseType(s32 id) {
  if (id < 0 || size_t(id) >= skWorldMaterialTable.size()) {
    return EWeaponCollisionResponseTypes::Default;
  }
  return skWorldMaterialTable[id];
}

bool CCollisionResponseData::ResponseTypeIsEnemyNormal(EWeaponCollisionResponseTypes type) {
  return (type >= EWeaponCollisionResponseTypes::Unknown19 && type <= EWeaponCollisionResponseTypes::AtomicAlpha);
}

bool CCollisionResponseData::ResponseTypeIsEnemySpecial(EWeaponCollisionResponseTypes type) {
  return (type >= EWeaponCollisionResponseTypes::Unknown44 && type <= EWeaponCollisionResponseTypes::Unknown68);
}

bool CCollisionResponseData::ResponseTypeIsEnemyShielded(EWeaponCollisionResponseTypes type) {
  return (type >= EWeaponCollisionResponseTypes::Unknown69 &&
          type <= EWeaponCollisionResponseTypes::AtomicAlphaReflect);
}

FourCC CCollisionResponseData::UncookedResType() { return SBIG('CRSM'); }

CFactoryFnReturn FCollisionResponseDataFactory(const SObjectTag& tag, CInputStream& in, const CVParamTransfer& vparms,
                                               CObjectReference*) {
  CSimplePool* sp = vparms.GetOwnedObj<CSimplePool*>();
  return TToken<CCollisionResponseData>::GetIObjObjectFor(std::make_unique<CCollisionResponseData>(in, sp));
}
} // namespace urde
<commit_msg>CCollisionResponseData: Join vector initializations into constructor initializer list<commit_after>#include "Runtime/Collision/CCollisionResponseData.hpp"

#include <array>

#include "Runtime/CRandom16.hpp"
#include "Runtime/CSimplePool.hpp"
#include "Runtime/Graphics/CModel.hpp"
#include "Runtime/Particle/CDecalDescription.hpp"
#include "Runtime/Particle/CElectricDescription.hpp"
#include "Runtime/Particle/CGenDescription.hpp"
#include "Runtime/Particle/CParticleDataFactory.hpp"
#include "Runtime/Particle/CSwooshDescription.hpp"

namespace urde {
namespace {
constexpr std::array skWorldMaterialTable{
    EWeaponCollisionResponseTypes::Default, EWeaponCollisionResponseTypes::Unknown2,
    EWeaponCollisionResponseTypes::Metal,   EWeaponCollisionResponseTypes::Grass,
    EWeaponCollisionResponseTypes::Ice,     EWeaponCollisionResponseTypes::Goo,
    EWeaponCollisionResponseTypes::Metal,   EWeaponCollisionResponseTypes::Wood,
    EWeaponCollisionResponseTypes::Grass,   EWeaponCollisionResponseTypes::Lava,
    EWeaponCollisionResponseTypes::Lava,    EWeaponCollisionResponseTypes::Ice,
    EWeaponCollisionResponseTypes::Mud,     EWeaponCollisionResponseTypes::Metal,
    EWeaponCollisionResponseTypes::Default, EWeaponCollisionResponseTypes::Goo,
    EWeaponCollisionResponseTypes::Goo,     EWeaponCollisionResponseTypes::Sand,
    EWeaponCollisionResponseTypes::Default, EWeaponCollisionResponseTypes::Default,
    EWeaponCollisionResponseTypes::Default, EWeaponCollisionResponseTypes::Metal,
    EWeaponCollisionResponseTypes::Default, EWeaponCollisionResponseTypes::Default,
    EWeaponCollisionResponseTypes::Default, EWeaponCollisionResponseTypes::Default,
    EWeaponCollisionResponseTypes::Default, EWeaponCollisionResponseTypes::Default,
    EWeaponCollisionResponseTypes::Default, EWeaponCollisionResponseTypes::Default,
    EWeaponCollisionResponseTypes::Default, EWeaponCollisionResponseTypes::Default,
};

constexpr s32 kInvalidSFX = -1;

constexpr std::array<FourCC, 94> kWCRTSFXIDs{{
    SBIG('NSFX'), SBIG('DSFX'), SBIG('CSFX'), SBIG('MSFX'), SBIG('GRFX'), SBIG('ICFX'), SBIG('GOFX'), SBIG('WSFX'),
    SBIG('WTFX'), SBIG('2MUD'), SBIG('2LAV'), SBIG('2SAN'), SBIG('2PRJ'), SBIG('DCFX'), SBIG('DSFX'), SBIG('DSHX'),
    SBIG('DEFX'), SBIG('ESFX'), SBIG('SHFX'), SBIG('BEFX'), SBIG('WWFX'), SBIG('TAFX'), SBIG('GTFX'), SBIG('SPFX'),
    SBIG('FPFX'), SBIG('FFFX'), SBIG('PAFX'), SBIG('BMFX'), SBIG('BFFX'), SBIG('PBFX'), SBIG('IBFX'), SBIG('4SVA'),
    SBIG('4RPR'), SBIG('4MTR'), SBIG('4PDS'), SBIG('4FLB'), SBIG('4DRN'), SBIG('4MRE'), SBIG('CZFX'), SBIG('JZAS'),
    SBIG('2ISE'), SBIG('2BSE'), SBIG('2ATB'), SBIG('2ATA'), SBIG('BSFX'), SBIG('WSFX'), SBIG('TSFX'), SBIG('GSFX'),
    SBIG('SSFX'), SBIG('FSFX'), SBIG('SFFX'), SBIG('PSFX'), SBIG('MSFX'), SBIG('SBFX'), SBIG('PBSX'), SBIG('IBSX'),
    SBIG('5SVA'), SBIG('5RPR'), SBIG('5MTR'), SBIG('5PDS'), SBIG('5FLB'), SBIG('5DRN'), SBIG('5MRE'), SBIG('CSFX'),
    SBIG('JZPS'), SBIG('4ISE'), SBIG('4BSE'), SBIG('4ATB'), SBIG('4ATA'), SBIG('BHFX'), SBIG('WHFX'), SBIG('THFX'),
    SBIG('GHFX'), SBIG('SHFX'), SBIG('FHFX'), SBIG('HFFX'), SBIG('PHFX'), SBIG('MHFX'), SBIG('HBFX'), SBIG('PBHX'),
    SBIG('IBHX'), SBIG('6SVA'), SBIG('6RPR'), SBIG('6MTR'), SBIG('6PDS'), SBIG('6FLB'), SBIG('6DRN'), SBIG('6MRE'),
    SBIG('CHFX'), SBIG('JZHS'), SBIG('6ISE'), SBIG('6BSE'), SBIG('6ATB'), SBIG('6ATA'),
}};

constexpr std::array<FourCC, 94> kWCRTIDs{{
    SBIG('NODP'), SBIG('DEFS'), SBIG('CRTS'), SBIG('MTLS'), SBIG('GRAS'), SBIG('ICEE'), SBIG('GOOO'), SBIG('WODS'),
    SBIG('WATR'), SBIG('1MUD'), SBIG('1LAV'), SBIG('1SAN'), SBIG('1PRJ'), SBIG('DCHR'), SBIG('DCHS'), SBIG('DCSH'),
    SBIG('DENM'), SBIG('DESP'), SBIG('DESH'), SBIG('BTLE'), SBIG('WASP'), SBIG('TALP'), SBIG('PTGM'), SBIG('SPIR'),
    SBIG('FPIR'), SBIG('FFLE'), SBIG('PARA'), SBIG('BMON'), SBIG('BFLR'), SBIG('PBOS'), SBIG('IBOS'), SBIG('1SVA'),
    SBIG('1RPR'), SBIG('1MTR'), SBIG('1PDS'), SBIG('1FLB'), SBIG('1DRN'), SBIG('1MRE'), SBIG('CHOZ'), SBIG('JZAP'),
    SBIG('1ISE'), SBIG('1BSE'), SBIG('1ATB'), SBIG('1ATA'), SBIG('BTSP'), SBIG('WWSP'), SBIG('TASP'), SBIG('TGSP'),
    SBIG('SPSP'), SBIG('FPSP'), SBIG('FFSP'), SBIG('PSSP'), SBIG('BMSP'), SBIG('BFSP'), SBIG('PBSP'), SBIG('IBSP'),
    SBIG('2SVA'), SBIG('2RPR'), SBIG('2MTR'), SBIG('2PDS'), SBIG('2FLB'), SBIG('2DRN'), SBIG('2MRE'), SBIG('CHSP'),
    SBIG('JZSP'), SBIG('3ISE'), SBIG('3BSE'), SBIG('3ATB'), SBIG('3ATA'), SBIG('BTSH'), SBIG('WWSH'), SBIG('TASH'),
    SBIG('TGSH'), SBIG('SPSH'), SBIG('FPSH'), SBIG('FFSH'), SBIG('PSSH'), SBIG('BMSH'), SBIG('BFSH'), SBIG('PBSH'),
    SBIG('IBSH'), SBIG('3SVA'), SBIG('3RPR'), SBIG('3MTR'), SBIG('3PDS'), SBIG('3FLB'), SBIG('3DRN'), SBIG('3MRE'),
    SBIG('CHSH'), SBIG('JZSH'), SBIG('5ISE'), SBIG('5BSE'), SBIG('5ATB'), SBIG('5ATA'),
}};

constexpr std::array<FourCC, 14> kWCRTDecalIDs{{
    SBIG('NCDL'),
    SBIG('DDCL'),
    SBIG('CODL'),
    SBIG('MEDL'),
    SBIG('GRDL'),
    SBIG('ICDL'),
    SBIG('GODL'),
    SBIG('WODL'),
    SBIG('WTDL'),
    SBIG('3MUD'),
    SBIG('3LAV'),
    SBIG('3SAN'),
    SBIG('CHDL'),
    SBIG('ENDL'),
}};

using CPF = CParticleDataFactory;
} // Anonymous namespace

void CCollisionResponseData::AddParticleSystemToResponse(EWeaponCollisionResponseTypes type, CInputStream& in,
                                                         CSimplePool* resPool) {
  const auto i = size_t(type);
  const std::vector<CAssetId> tracker(8);
  x0_generators[i].emplace(CPF::GetChildGeneratorDesc(in, resPool, tracker).m_token);
}

bool CCollisionResponseData::CheckAndAddDecalToResponse(FourCC clsId, CInputStream& in, CSimplePool* resPool) {
  size_t i = 0;
  for (const FourCC& type : kWCRTDecalIDs) {
    if (type == clsId) {
      const FourCC cls = CPF::GetClassID(in);
      if (cls == SBIG('NONE')) {
        return true;
      }

      const CAssetId id{u64(in.readUint32Big())};
      if (!id.IsValid()) {
        return true;
      }

      x20_decals[i].emplace(resPool->GetObj({FOURCC('DPSC'), id}));
      return true;
    }
    i++;
  }
  return false;
}

bool CCollisionResponseData::CheckAndAddSoundFXToResponse(FourCC clsId, CInputStream& in) {
  size_t i = 0;
  for (const FourCC& type : kWCRTSFXIDs) {
    if (type == clsId) {
      const FourCC cls = CPF::GetClassID(in);
      if (cls == SBIG('NONE')) {
        return true;
      }

      x10_sfx[i] = CPF::GetInt(in);
      return true;
    }
    i++;
  }

  return false;
}

bool CCollisionResponseData::CheckAndAddParticleSystemToResponse(FourCC clsId, CInputStream& in, CSimplePool* resPool) {
  size_t i = 0;
  for (const FourCC& type : kWCRTIDs) {
    if (type == clsId) {
      AddParticleSystemToResponse(EWeaponCollisionResponseTypes(i), in, resPool);
      return true;
    }
    i++;
  }
  return false;
}

bool CCollisionResponseData::CheckAndAddResourceToResponse(FourCC clsId, CInputStream& in, CSimplePool* resPool) {
  if (CheckAndAddParticleSystemToResponse(clsId, in, resPool))
    return true;
  if (CheckAndAddSoundFXToResponse(clsId, in))
    return true;
  if (CheckAndAddDecalToResponse(clsId, in, resPool))
    return true;

  return false;
}

CCollisionResponseData::CCollisionResponseData(CInputStream& in, CSimplePool* resPool)
: x0_generators(94), x10_sfx(94, kInvalidSFX), x20_decals(94), x30_RNGE(50.f), x34_FOFF(0.2f) {
  FourCC clsId = CPF::GetClassID(in);
  if (clsId == UncookedResType()) {
    CRandom16 rand;
    CGlobalRandom gr(rand);

    while (clsId != SBIG('_END')) {
      clsId = CPF::GetClassID(in);
      if (CheckAndAddResourceToResponse(clsId, in, resPool))
        continue;

      if (clsId == SBIG('RNGE')) {
        CPF::GetClassID(in);
        x30_RNGE = CPF::GetReal(in);
      } else if (clsId == SBIG('FOFF')) {
        CPF::GetClassID(in);
        x34_FOFF = CPF::GetReal(in);
      }
    }
  }
}

const std::optional<TLockedToken<CGenDescription>>&
CCollisionResponseData::GetParticleDescription(EWeaponCollisionResponseTypes type) const {
  if (x0_generators[size_t(type)]) {
    return x0_generators[size_t(type)];
  }

  bool foundType = false;
  if (ResponseTypeIsEnemyNormal(type)) {
    type = EWeaponCollisionResponseTypes::EnemyNormal;
    foundType = true;
  } else if (ResponseTypeIsEnemySpecial(type)) {
    type = EWeaponCollisionResponseTypes::EnemySpecial;
    foundType = true;
  } else if (ResponseTypeIsEnemyShielded(type)) {
    type = EWeaponCollisionResponseTypes::EnemyShielded;
    foundType = true;
  }

  if (foundType && !x0_generators[size_t(type)]) {
    type = EWeaponCollisionResponseTypes::EnemyNormal;
  }

  if (!x0_generators[size_t(type)] && type != EWeaponCollisionResponseTypes::None) {
    type = EWeaponCollisionResponseTypes::Default;
  }

  return x0_generators[size_t(type)];
}

const std::optional<TLockedToken<CDecalDescription>>&
CCollisionResponseData::GetDecalDescription(EWeaponCollisionResponseTypes type) const {
  return x20_decals[size_t(type)];
}

s32 CCollisionResponseData::GetSoundEffectId(EWeaponCollisionResponseTypes type) const {
  if (x10_sfx[size_t(type)] == kInvalidSFX) {
    if (ResponseTypeIsEnemyNormal(type))
      type = EWeaponCollisionResponseTypes::EnemyNormal;
    else if (ResponseTypeIsEnemySpecial(type))
      type = EWeaponCollisionResponseTypes::EnemySpecial;
    else if (ResponseTypeIsEnemyShielded(type))
      type = EWeaponCollisionResponseTypes::EnemyShielded;
    else
      type = EWeaponCollisionResponseTypes::Default;
  }

  return x10_sfx[size_t(type)];
}

EWeaponCollisionResponseTypes CCollisionResponseData::GetWorldCollisionResponseType(s32 id) {
  if (id < 0 || size_t(id) >= skWorldMaterialTable.size()) {
    return EWeaponCollisionResponseTypes::Default;
  }
  return skWorldMaterialTable[id];
}

bool CCollisionResponseData::ResponseTypeIsEnemyNormal(EWeaponCollisionResponseTypes type) {
  return (type >= EWeaponCollisionResponseTypes::Unknown19 && type <= EWeaponCollisionResponseTypes::AtomicAlpha);
}

bool CCollisionResponseData::ResponseTypeIsEnemySpecial(EWeaponCollisionResponseTypes type) {
  return (type >= EWeaponCollisionResponseTypes::Unknown44 && type <= EWeaponCollisionResponseTypes::Unknown68);
}

bool CCollisionResponseData::ResponseTypeIsEnemyShielded(EWeaponCollisionResponseTypes type) {
  return (type >= EWeaponCollisionResponseTypes::Unknown69 &&
          type <= EWeaponCollisionResponseTypes::AtomicAlphaReflect);
}

FourCC CCollisionResponseData::UncookedResType() { return SBIG('CRSM'); }

CFactoryFnReturn FCollisionResponseDataFactory(const SObjectTag& tag, CInputStream& in, const CVParamTransfer& vparms,
                                               CObjectReference*) {
  CSimplePool* sp = vparms.GetOwnedObj<CSimplePool*>();
  return TToken<CCollisionResponseData>::GetIObjObjectFor(std::make_unique<CCollisionResponseData>(in, sp));
}
} // namespace urde
<|endoftext|>


<commit_before>
#include <gameplay/GameplayModule.hpp>
#include <Constants.hpp>
#include <protobuf/LogFrame.pb.h>
#include <Robot.hpp>
#include <SystemState.hpp>

#include <stdio.h>
#include <iostream>
#include <boost/foreach.hpp>
#include <boost/make_shared.hpp>

//	for python stuff
#include <gameplay2/robocup-py.hpp>

using namespace std;
using namespace boost;
using namespace boost::python;

Gameplay::GameplayModule::GameplayModule(SystemState *state):
	_mutex(QMutex::Recursive)
{
	_state = state;

	_centerMatrix = Geometry2d::TransformMatrix::translate(Geometry2d::Point(0, Field_Length / 2));
	_oppMatrix = Geometry2d::TransformMatrix::translate(Geometry2d::Point(0, Field_Length)) *
				Geometry2d::TransformMatrix::rotate(180);

	//// Make an obstacle to cover the opponent's half of the field except for one robot diameter across the center line.
	PolygonObstacle *sidePolygon = new PolygonObstacle;
	_sideObstacle = ObstaclePtr(sidePolygon);
	float x = Field_Width / 2 + Field_Border;
	const float y1 = Field_Length / 2;
	const float y2 = Field_Length + Field_Border;
	const float r = Field_CenterRadius;
	sidePolygon->polygon.vertices.push_back(Geometry2d::Point(-x, y1));
	sidePolygon->polygon.vertices.push_back(Geometry2d::Point(-r, y1));
	sidePolygon->polygon.vertices.push_back(Geometry2d::Point(0, y1 + r));
	sidePolygon->polygon.vertices.push_back(Geometry2d::Point(r, y1));
	sidePolygon->polygon.vertices.push_back(Geometry2d::Point(x, y1));
	sidePolygon->polygon.vertices.push_back(Geometry2d::Point(x, y2));
	sidePolygon->polygon.vertices.push_back(Geometry2d::Point(-x, y2));

	float y = -Field_Border;
	float deadspace = Field_Border;
	x = Floor_Width/2.0f;
	PolygonObstacle* floorObstacle = new PolygonObstacle;
	floorObstacle->polygon.vertices.push_back(Geometry2d::Point(-x, y));
	floorObstacle->polygon.vertices.push_back(Geometry2d::Point(-x, y-1));
	floorObstacle->polygon.vertices.push_back(Geometry2d::Point(x, y-1));
	floorObstacle->polygon.vertices.push_back(Geometry2d::Point(x, y));
	_nonFloor[0] = ObstaclePtr(floorObstacle);

	y = Field_Length + Field_Border;
	floorObstacle = new PolygonObstacle;
	floorObstacle->polygon.vertices.push_back(Geometry2d::Point(-x, y));
	floorObstacle->polygon.vertices.push_back(Geometry2d::Point(-x, y+1));
	floorObstacle->polygon.vertices.push_back(Geometry2d::Point(x, y+1));
	floorObstacle->polygon.vertices.push_back(Geometry2d::Point(x, y));
	_nonFloor[1] = ObstaclePtr(floorObstacle);

	y = Floor_Length;
	floorObstacle = new PolygonObstacle;
	floorObstacle->polygon.vertices.push_back(Geometry2d::Point(-x, -deadspace));
	floorObstacle->polygon.vertices.push_back(Geometry2d::Point(-x-1, -deadspace));
	floorObstacle->polygon.vertices.push_back(Geometry2d::Point(-x-1, y));
	floorObstacle->polygon.vertices.push_back(Geometry2d::Point(-x, y));
	_nonFloor[2] = ObstaclePtr(floorObstacle);

	floorObstacle = new PolygonObstacle;
	floorObstacle->polygon.vertices.push_back(Geometry2d::Point(x, -deadspace));
	floorObstacle->polygon.vertices.push_back(Geometry2d::Point(x+1, -deadspace));
	floorObstacle->polygon.vertices.push_back(Geometry2d::Point(x+1, y));
	floorObstacle->polygon.vertices.push_back(Geometry2d::Point(x, y));
	_nonFloor[3] = ObstaclePtr(floorObstacle);

	PolygonObstacle* goalArea = new PolygonObstacle;
	const float halfFlat = Field_GoalFlat/2.0;
	const float radius = Field_ArcRadius;
	goalArea->polygon.vertices.push_back(Geometry2d::Point(-halfFlat, 0));
	goalArea->polygon.vertices.push_back(Geometry2d::Point(-halfFlat, radius));
	goalArea->polygon.vertices.push_back(Geometry2d::Point( halfFlat, radius));
	goalArea->polygon.vertices.push_back(Geometry2d::Point( halfFlat, 0));
	_goalArea.add(ObstaclePtr(goalArea));
	_goalArea.add(ObstaclePtr(new CircleObstacle(Geometry2d::Point(-halfFlat, 0), radius)));
	_goalArea.add(ObstaclePtr(new CircleObstacle(Geometry2d::Point(halfFlat, 0), radius)));

	_ourHalf = std::make_shared<PolygonObstacle>();
	_ourHalf->polygon.vertices.push_back(Geometry2d::Point(-x, -Field_Border));
	_ourHalf->polygon.vertices.push_back(Geometry2d::Point(-x, y1));
	_ourHalf->polygon.vertices.push_back(Geometry2d::Point(x, y1));
	_ourHalf->polygon.vertices.push_back(Geometry2d::Point(x, -Field_Border));

	_opponentHalf = std::make_shared<PolygonObstacle>();
	_opponentHalf->polygon.vertices.push_back(Geometry2d::Point(-x, y1));
	_opponentHalf->polygon.vertices.push_back(Geometry2d::Point(-x, y2));
	_opponentHalf->polygon.vertices.push_back(Geometry2d::Point(x, y2));
	_opponentHalf->polygon.vertices.push_back(Geometry2d::Point(x, y1));

	_goalieID = -1;

	//
	//	setup python interpreter
	//
	try {
        cout << "Initializing embedded python interpreter..." << endl;

        //  this tells python how to load the robocup module
        //  it has to be done before Py_Initialize()
        PyImport_AppendInittab("robocup", &PyInit_robocup);

        //	we use Py_InitializeEx(0) instead of regular Py_Initialize() so that Ctrl-C kills soccer as expected
        Py_InitializeEx(0);

        object main_module((handle<>(borrowed(PyImport_AddModule("__main__")))));
        _mainPyNamespace = main_module.attr("__dict__");

        object robocup_module((handle<>(PyImport_ImportModule("robocup"))));
        _mainPyNamespace["robocup"] = robocup_module;

        //	FIXME: make this a relative path
        //	add gameplay directory to python import path (so import XXX) will look in the right directory
        handle<>ignored2((PyRun_String("import sys; sys.path.append('/home/robojackets/src/robocup-software-dev/soccer/gameplay2')",
            Py_file_input,
            _mainPyNamespace.ptr(),
            _mainPyNamespace.ptr())));

        //	instantiate the root play
        handle<>ignored3((PyRun_String("from root_play import *; root_play = RootPlay()",
            Py_file_input,
            _mainPyNamespace.ptr(),
            _mainPyNamespace.ptr())));
    } catch (error_already_set) {
        PyErr_Print();
        throw new runtime_error("Unable to initialize embedded python interpreter");
    }
}

/*
void Gameplay::GameplayModule::createGoalie()
{
	if (!_goalie)
	{
		printf("Creating goalie behavior.\n");
  		_goalie = new Behaviors::Goalie(this);
	}
}

void Gameplay::GameplayModule::removeGoalie()
{
	if (_goalie)
	{
		printf("Removing goalie behavior.\n");
		delete _goalie;
		_goalie = 0;
	}
}

void Gameplay::GameplayModule::updatePlay() {
	const bool verbose = false;

	/// important scenarios:
	///  - no current plays - must pick a new one
	///  - no available plays - must do nothing
	///  - current play is fine, must be run
	///  - current play has ended, must select new and run
	///  - current play is not applicable/failed, must kill, select new and run
	///  - new goalie, select new play (may reselect current play, which much be assigned new robots)

	/// Update play scores.
	/// The GUI thread needs this for the Plays tab and we will use it later
	/// to determine the new play.
	BOOST_FOREACH(PlayFactory *factory, PlayFactory::factories())
	{
	factory->lastScore = factory->score(this);
	}

	if (	_playDone || 							/// New play if old one was complete
			!_currentPlay ||						/// There is no current play
			isinf(_currentPlayFactory->lastScore) || /// Current play doesn't apply anymore
			!_currentPlayFactory->enabled			/// Current play was disabled
	)
	{
		if (verbose) cout << "  Selecting a new play" << endl;
		_playDone = false;

		/// Find the next play
		PlayFactory *bestPlay = 0;
		/// Pick a new play
		float bestScore = 0;

		/// Find the best applicable play
		BOOST_FOREACH(PlayFactory *factory, PlayFactory::factories())
		{
			if (factory->enabled)
			{
				float score = factory->lastScore;
				if (!isinf(score) && (!bestPlay || score < bestScore))
				{
					bestScore = score;
					bestPlay = factory;
				}
			}
		}

		/// Start the play if it's not current.
		if (bestPlay)
		{
			if (bestPlay != _currentPlayFactory)
			{
				clearAvoidBallRadii();

				_currentPlayFactory = bestPlay;
				_currentPlay = std::shared_ptr<Play>(_currentPlayFactory->create(this));
			}
		} else {
			/// No usable plays
			_currentPlay.reset();
			_currentPlayFactory = 0;
		}
	}
}
*/

void Gameplay::GameplayModule::clearAvoidBallRadii() {
	BOOST_FOREACH(OurRobot* robot, _state->self)
	{
		if (robot) {
			robot->resetAvoidBall();
		}
	}
}

/**
 * returns the group of obstacles for the field
 */
ObstacleGroup Gameplay::GameplayModule::globalObstacles() const {
	ObstacleGroup obstacles;
	if (_state->gameState.stayOnSide())
	{
		obstacles.add(_sideObstacle);
	}

	if (!_state->logFrame->use_our_half())
	{
		obstacles.add(_ourHalf);
	}

	if (!_state->logFrame->use_opponent_half())
	{
		obstacles.add(_opponentHalf);
	}

	/// Add non floor obstacles
	BOOST_FOREACH(const ObstaclePtr& ptr, _nonFloor)
	{
		obstacles.add(ptr);
	}
	return obstacles;
}

/**
 * runs the current play
 */
void Gameplay::GameplayModule::run()
{
	QMutexLocker lock(&_mutex);

	bool verbose = false;
	if (verbose) cout << "Starting GameplayModule::run()" << endl;

	_ballMatrix = Geometry2d::TransformMatrix::translate(_state->ball.pos);

	/// perform state variable updates on robots
	/// Currently - only the timer for the kicker charger
	BOOST_FOREACH(OurRobot* robot, _state->self)
	{
		if (robot) {
			robot->update();
			robot->resetForNextIteration();
		}
	}

	/// Build a list of visible robots
	_playRobots.clear();
	BOOST_FOREACH(OurRobot *r, _state->self)
	{
		if (r->visible && r->rxIsFresh())
		{
			_playRobots.insert(r);
		}
	}

	//	FIXME: remove manualID robot?

	try {
		//	vector of shared pointers to pass to python
		std::vector<OurRobot *> *botVector = new std::vector<OurRobot *>();
		for (auto itr = _playRobots.begin(); itr != _playRobots.end(); itr++) {
			botVector->push_back(*itr);
		}

		getRootPlay().attr("robots") = botVector;
	} catch (error_already_set) {
		PyErr_Print();
		throw new runtime_error("Error trying to send robots to python");
	}

	/// Run the current play
	if (verbose) cout << "  Running play" << endl;
	try {
		getRootPlay().attr("run")();
	} catch (error_already_set) {
        PyErr_Print();
        throw new runtime_error("Error trying to run root play");
    }

	/// determine global obstacles - field requirements
	/// Two versions - one set with goal area, another without for goalie
	ObstacleGroup global_obstacles = globalObstacles();
	ObstacleGroup obstacles_with_goal = global_obstacles;
	obstacles_with_goal.add(_goalArea);

	/// execute motion planning for each robot
	BOOST_FOREACH(OurRobot* r, _state->self) {
		if (r && r->visible) {
			/// set obstacles for the robots
			if (r->shell() == _goalieID)
				r->replanIfNeeded(global_obstacles); /// just for goalie
			else
				r->replanIfNeeded(obstacles_with_goal); /// all other robots
		}
	}

	/// visualize
	if (_state->gameState.stayAwayFromBall() && _state->ball.valid)
	{
		_state->drawCircle(_state->ball.pos, Field_CenterRadius, Qt::black, "Rules");
	}

	if (verbose) cout << "Finishing GameplayModule::run()" << endl;

	if(_state->gameState.ourScore > _our_score_last_frame)
	{
		BOOST_FOREACH(OurRobot* r, _state->self)
		{
			r->sing();
		}
	}
	_our_score_last_frame = _state->gameState.ourScore;
}

#pragma mark python

boost::python::object Gameplay::GameplayModule::getRootPlay() {
	return _mainPyNamespace["root_play"];
}
<commit_msg>unhardcoded path to python modules<commit_after>
#include <gameplay/GameplayModule.hpp>
#include <Constants.hpp>
#include <protobuf/LogFrame.pb.h>
#include <Robot.hpp>
#include <SystemState.hpp>

#include <stdio.h>
#include <iostream>
#include <boost/foreach.hpp>
#include <boost/make_shared.hpp>

//	for python stuff
#include <gameplay2/robocup-py.hpp>

using namespace std;
using namespace boost;
using namespace boost::python;

Gameplay::GameplayModule::GameplayModule(SystemState *state):
	_mutex(QMutex::Recursive)
{
	_state = state;

	_centerMatrix = Geometry2d::TransformMatrix::translate(Geometry2d::Point(0, Field_Length / 2));
	_oppMatrix = Geometry2d::TransformMatrix::translate(Geometry2d::Point(0, Field_Length)) *
				Geometry2d::TransformMatrix::rotate(180);

	//// Make an obstacle to cover the opponent's half of the field except for one robot diameter across the center line.
	PolygonObstacle *sidePolygon = new PolygonObstacle;
	_sideObstacle = ObstaclePtr(sidePolygon);
	float x = Field_Width / 2 + Field_Border;
	const float y1 = Field_Length / 2;
	const float y2 = Field_Length + Field_Border;
	const float r = Field_CenterRadius;
	sidePolygon->polygon.vertices.push_back(Geometry2d::Point(-x, y1));
	sidePolygon->polygon.vertices.push_back(Geometry2d::Point(-r, y1));
	sidePolygon->polygon.vertices.push_back(Geometry2d::Point(0, y1 + r));
	sidePolygon->polygon.vertices.push_back(Geometry2d::Point(r, y1));
	sidePolygon->polygon.vertices.push_back(Geometry2d::Point(x, y1));
	sidePolygon->polygon.vertices.push_back(Geometry2d::Point(x, y2));
	sidePolygon->polygon.vertices.push_back(Geometry2d::Point(-x, y2));

	float y = -Field_Border;
	float deadspace = Field_Border;
	x = Floor_Width/2.0f;
	PolygonObstacle* floorObstacle = new PolygonObstacle;
	floorObstacle->polygon.vertices.push_back(Geometry2d::Point(-x, y));
	floorObstacle->polygon.vertices.push_back(Geometry2d::Point(-x, y-1));
	floorObstacle->polygon.vertices.push_back(Geometry2d::Point(x, y-1));
	floorObstacle->polygon.vertices.push_back(Geometry2d::Point(x, y));
	_nonFloor[0] = ObstaclePtr(floorObstacle);

	y = Field_Length + Field_Border;
	floorObstacle = new PolygonObstacle;
	floorObstacle->polygon.vertices.push_back(Geometry2d::Point(-x, y));
	floorObstacle->polygon.vertices.push_back(Geometry2d::Point(-x, y+1));
	floorObstacle->polygon.vertices.push_back(Geometry2d::Point(x, y+1));
	floorObstacle->polygon.vertices.push_back(Geometry2d::Point(x, y));
	_nonFloor[1] = ObstaclePtr(floorObstacle);

	y = Floor_Length;
	floorObstacle = new PolygonObstacle;
	floorObstacle->polygon.vertices.push_back(Geometry2d::Point(-x, -deadspace));
	floorObstacle->polygon.vertices.push_back(Geometry2d::Point(-x-1, -deadspace));
	floorObstacle->polygon.vertices.push_back(Geometry2d::Point(-x-1, y));
	floorObstacle->polygon.vertices.push_back(Geometry2d::Point(-x, y));
	_nonFloor[2] = ObstaclePtr(floorObstacle);

	floorObstacle = new PolygonObstacle;
	floorObstacle->polygon.vertices.push_back(Geometry2d::Point(x, -deadspace));
	floorObstacle->polygon.vertices.push_back(Geometry2d::Point(x+1, -deadspace));
	floorObstacle->polygon.vertices.push_back(Geometry2d::Point(x+1, y));
	floorObstacle->polygon.vertices.push_back(Geometry2d::Point(x, y));
	_nonFloor[3] = ObstaclePtr(floorObstacle);

	PolygonObstacle* goalArea = new PolygonObstacle;
	const float halfFlat = Field_GoalFlat/2.0;
	const float radius = Field_ArcRadius;
	goalArea->polygon.vertices.push_back(Geometry2d::Point(-halfFlat, 0));
	goalArea->polygon.vertices.push_back(Geometry2d::Point(-halfFlat, radius));
	goalArea->polygon.vertices.push_back(Geometry2d::Point( halfFlat, radius));
	goalArea->polygon.vertices.push_back(Geometry2d::Point( halfFlat, 0));
	_goalArea.add(ObstaclePtr(goalArea));
	_goalArea.add(ObstaclePtr(new CircleObstacle(Geometry2d::Point(-halfFlat, 0), radius)));
	_goalArea.add(ObstaclePtr(new CircleObstacle(Geometry2d::Point(halfFlat, 0), radius)));

	_ourHalf = std::make_shared<PolygonObstacle>();
	_ourHalf->polygon.vertices.push_back(Geometry2d::Point(-x, -Field_Border));
	_ourHalf->polygon.vertices.push_back(Geometry2d::Point(-x, y1));
	_ourHalf->polygon.vertices.push_back(Geometry2d::Point(x, y1));
	_ourHalf->polygon.vertices.push_back(Geometry2d::Point(x, -Field_Border));

	_opponentHalf = std::make_shared<PolygonObstacle>();
	_opponentHalf->polygon.vertices.push_back(Geometry2d::Point(-x, y1));
	_opponentHalf->polygon.vertices.push_back(Geometry2d::Point(-x, y2));
	_opponentHalf->polygon.vertices.push_back(Geometry2d::Point(x, y2));
	_opponentHalf->polygon.vertices.push_back(Geometry2d::Point(x, y1));

	_goalieID = -1;

	//
	//	setup python interpreter
	//
	try {
        cout << "Initializing embedded python interpreter..." << endl;

        //  this tells python how to load the robocup module
        //  it has to be done before Py_Initialize()
        PyImport_AppendInittab("robocup", &PyInit_robocup);

        //	we use Py_InitializeEx(0) instead of regular Py_Initialize() so that Ctrl-C kills soccer as expected
        Py_InitializeEx(0);

        object main_module((handle<>(borrowed(PyImport_AddModule("__main__")))));
        _mainPyNamespace = main_module.attr("__dict__");

        object robocup_module((handle<>(PyImport_ImportModule("robocup"))));
        _mainPyNamespace["robocup"] = robocup_module;

        //	add gameplay directory to python import path (so import XXX) will look in the right directory
        handle<>ignored2((PyRun_String("import sys; sys.path.append('../soccer/gameplay2')",
            Py_file_input,
            _mainPyNamespace.ptr(),
            _mainPyNamespace.ptr())));

        //	instantiate the root play
        handle<>ignored3((PyRun_String("from root_play import *; root_play = RootPlay()",
            Py_file_input,
            _mainPyNamespace.ptr(),
            _mainPyNamespace.ptr())));
    } catch (error_already_set) {
        PyErr_Print();
        throw new runtime_error("Unable to initialize embedded python interpreter");
    }
}

/*
void Gameplay::GameplayModule::createGoalie()
{
	if (!_goalie)
	{
		printf("Creating goalie behavior.\n");
  		_goalie = new Behaviors::Goalie(this);
	}
}

void Gameplay::GameplayModule::removeGoalie()
{
	if (_goalie)
	{
		printf("Removing goalie behavior.\n");
		delete _goalie;
		_goalie = 0;
	}
}

void Gameplay::GameplayModule::updatePlay() {
	const bool verbose = false;

	/// important scenarios:
	///  - no current plays - must pick a new one
	///  - no available plays - must do nothing
	///  - current play is fine, must be run
	///  - current play has ended, must select new and run
	///  - current play is not applicable/failed, must kill, select new and run
	///  - new goalie, select new play (may reselect current play, which much be assigned new robots)

	/// Update play scores.
	/// The GUI thread needs this for the Plays tab and we will use it later
	/// to determine the new play.
	BOOST_FOREACH(PlayFactory *factory, PlayFactory::factories())
	{
	factory->lastScore = factory->score(this);
	}

	if (	_playDone || 							/// New play if old one was complete
			!_currentPlay ||						/// There is no current play
			isinf(_currentPlayFactory->lastScore) || /// Current play doesn't apply anymore
			!_currentPlayFactory->enabled			/// Current play was disabled
	)
	{
		if (verbose) cout << "  Selecting a new play" << endl;
		_playDone = false;

		/// Find the next play
		PlayFactory *bestPlay = 0;
		/// Pick a new play
		float bestScore = 0;

		/// Find the best applicable play
		BOOST_FOREACH(PlayFactory *factory, PlayFactory::factories())
		{
			if (factory->enabled)
			{
				float score = factory->lastScore;
				if (!isinf(score) && (!bestPlay || score < bestScore))
				{
					bestScore = score;
					bestPlay = factory;
				}
			}
		}

		/// Start the play if it's not current.
		if (bestPlay)
		{
			if (bestPlay != _currentPlayFactory)
			{
				clearAvoidBallRadii();

				_currentPlayFactory = bestPlay;
				_currentPlay = std::shared_ptr<Play>(_currentPlayFactory->create(this));
			}
		} else {
			/// No usable plays
			_currentPlay.reset();
			_currentPlayFactory = 0;
		}
	}
}
*/

void Gameplay::GameplayModule::clearAvoidBallRadii() {
	BOOST_FOREACH(OurRobot* robot, _state->self)
	{
		if (robot) {
			robot->resetAvoidBall();
		}
	}
}

/**
 * returns the group of obstacles for the field
 */
ObstacleGroup Gameplay::GameplayModule::globalObstacles() const {
	ObstacleGroup obstacles;
	if (_state->gameState.stayOnSide())
	{
		obstacles.add(_sideObstacle);
	}

	if (!_state->logFrame->use_our_half())
	{
		obstacles.add(_ourHalf);
	}

	if (!_state->logFrame->use_opponent_half())
	{
		obstacles.add(_opponentHalf);
	}

	/// Add non floor obstacles
	BOOST_FOREACH(const ObstaclePtr& ptr, _nonFloor)
	{
		obstacles.add(ptr);
	}
	return obstacles;
}

/**
 * runs the current play
 */
void Gameplay::GameplayModule::run()
{
	QMutexLocker lock(&_mutex);

	bool verbose = false;
	if (verbose) cout << "Starting GameplayModule::run()" << endl;

	_ballMatrix = Geometry2d::TransformMatrix::translate(_state->ball.pos);

	/// perform state variable updates on robots
	/// Currently - only the timer for the kicker charger
	BOOST_FOREACH(OurRobot* robot, _state->self)
	{
		if (robot) {
			robot->update();
			robot->resetForNextIteration();
		}
	}

	/// Build a list of visible robots
	_playRobots.clear();
	BOOST_FOREACH(OurRobot *r, _state->self)
	{
		if (r->visible && r->rxIsFresh())
		{
			_playRobots.insert(r);
		}
	}

	//	FIXME: remove manualID robot?

	try {
		//	vector of shared pointers to pass to python
		std::vector<OurRobot *> *botVector = new std::vector<OurRobot *>();
		for (auto itr = _playRobots.begin(); itr != _playRobots.end(); itr++) {
			botVector->push_back(*itr);
		}

		getRootPlay().attr("robots") = botVector;
	} catch (error_already_set) {
		PyErr_Print();
		throw new runtime_error("Error trying to send robots to python");
	}

	/// Run the current play
	if (verbose) cout << "  Running play" << endl;
	try {
		getRootPlay().attr("run")();
	} catch (error_already_set) {
        PyErr_Print();
        throw new runtime_error("Error trying to run root play");
    }

	/// determine global obstacles - field requirements
	/// Two versions - one set with goal area, another without for goalie
	ObstacleGroup global_obstacles = globalObstacles();
	ObstacleGroup obstacles_with_goal = global_obstacles;
	obstacles_with_goal.add(_goalArea);

	/// execute motion planning for each robot
	BOOST_FOREACH(OurRobot* r, _state->self) {
		if (r && r->visible) {
			/// set obstacles for the robots
			if (r->shell() == _goalieID)
				r->replanIfNeeded(global_obstacles); /// just for goalie
			else
				r->replanIfNeeded(obstacles_with_goal); /// all other robots
		}
	}

	/// visualize
	if (_state->gameState.stayAwayFromBall() && _state->ball.valid)
	{
		_state->drawCircle(_state->ball.pos, Field_CenterRadius, Qt::black, "Rules");
	}

	if (verbose) cout << "Finishing GameplayModule::run()" << endl;

	if(_state->gameState.ourScore > _our_score_last_frame)
	{
		BOOST_FOREACH(OurRobot* r, _state->self)
		{
			r->sing();
		}
	}
	_our_score_last_frame = _state->gameState.ourScore;
}

#pragma mark python

boost::python::object Gameplay::GameplayModule::getRootPlay() {
	return _mainPyNamespace["root_play"];
}
<|endoftext|>


<commit_before>/******************************************************************************\

          This file is part of the C! library.  A.K.A the cbang library.

                Copyright (c) 2003-2019, Cauldron Development LLC
                   Copyright (c) 2003-2017, Stanford University
                               All rights reserved.

         The C! library is free software: you can redistribute it and/or
        modify it under the terms of the GNU Lesser General Public License
       as published by the Free Software Foundation, either version 2.1 of
               the License, or (at your option) any later version.

        The C! library is distributed in the hope that it will be useful,
          but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                 Lesser General Public License for more details.

         You should have received a copy of the GNU Lesser General Public
                 License along with the C! library.  If not, see
                         <http://www.gnu.org/licenses/>.

        In addition, BSD licensing may be granted on a case by case basis
        by written permission from at least one of the copyright holders.
           You may request written permission by emailing the authors.

                  For information regarding this software email:
                                 Joseph Coffland
                          joseph@cauldrondevelopment.com

\******************************************************************************/

#include "TransferWrite.h"

#include <cbang/Catch.h>
#include <cbang/openssl/SSL.h>
#include <cbang/log/Logger.h>

#ifdef HAVE_VALGRIND
#include <valgrind/memcheck.h>
#endif

#include <event2/util.h>
#include <event2/buffer.h>

using namespace cb::Event;
using namespace cb;

TransferWrite::TransferWrite(int fd, const SmartPointer<SSL> &ssl, cb_t cb,
                             const Buffer &buffer) :
  Transfer(fd, ssl, cb, buffer.getLength()), buffer(buffer) {checkFinished();}

int TransferWrite::transfer() {
  int bytes = 0;

  while (true) {
    int ret = write(buffer, buffer.getLength());
    LOG_DEBUG(4, CBANG_FUNC << "() ret=" << ret);

    if (!bytes && ret < 0) finished = true;
    else checkFinished();

    if (finished || ret <= 0)
      return bytes ? bytes : ((success || wantsRead()) ? ret : -1);

    bytes += ret;
  }
}

int TransferWrite::write(Buffer &buffer, unsigned length) {
  if (!length) return 0;

#ifdef HAVE_OPENSSL
  if (ssl.isSet()) {
    try {
      iovec space;
      buffer.peek(length, space);
      if (!space.iov_len) return -1; // No data

      int ret = ssl->write((char *)space.iov_base, space.iov_len);
      if (0 < ret) buffer.drain(ret);

      return ret;

    } CATCH_ERROR;
    return -1;
  }
#endif // HAVE_OPENSSL

  return buffer.write(fd, length);
}

void TransferWrite::checkFinished() {
  if (!buffer.getLength()) finished = success = true;
}
<commit_msg>Fix for SSL write transfer<commit_after>/******************************************************************************\

          This file is part of the C! library.  A.K.A the cbang library.

                Copyright (c) 2003-2019, Cauldron Development LLC
                   Copyright (c) 2003-2017, Stanford University
                               All rights reserved.

         The C! library is free software: you can redistribute it and/or
        modify it under the terms of the GNU Lesser General Public License
       as published by the Free Software Foundation, either version 2.1 of
               the License, or (at your option) any later version.

        The C! library is distributed in the hope that it will be useful,
          but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                 Lesser General Public License for more details.

         You should have received a copy of the GNU Lesser General Public
                 License along with the C! library.  If not, see
                         <http://www.gnu.org/licenses/>.

        In addition, BSD licensing may be granted on a case by case basis
        by written permission from at least one of the copyright holders.
           You may request written permission by emailing the authors.

                  For information regarding this software email:
                                 Joseph Coffland
                          joseph@cauldrondevelopment.com

\******************************************************************************/

#include "TransferWrite.h"

#include <cbang/Catch.h>
#include <cbang/openssl/SSL.h>
#include <cbang/log/Logger.h>

#ifdef HAVE_VALGRIND
#include <valgrind/memcheck.h>
#endif

#include <event2/util.h>
#include <event2/buffer.h>

using namespace cb::Event;
using namespace cb;

TransferWrite::TransferWrite(int fd, const SmartPointer<SSL> &ssl, cb_t cb,
                             const Buffer &buffer) :
  Transfer(fd, ssl, cb, buffer.getLength()), buffer(buffer) {checkFinished();}

int TransferWrite::transfer() {
  int bytes = 0;

  while (true) {
    int ret = write(buffer, buffer.getLength());
    LOG_DEBUG(4, CBANG_FUNC << "() ret=" << ret);

    if (!bytes && ret < 0) finished = true;
    else checkFinished();

    if (finished || ret <= 0)
      return bytes ? bytes :
        ((success || wantsRead() || wantsWrite()) ? ret : -1);

    bytes += ret;
  }
}

int TransferWrite::write(Buffer &buffer, unsigned length) {
  if (!length) return 0;

#ifdef HAVE_OPENSSL
  if (ssl.isSet()) {
    try {
      iovec space;
      buffer.peek(length, space);
      if (!space.iov_len) return -1; // No data

      int ret = ssl->write((char *)space.iov_base, space.iov_len);
      if (0 < ret) buffer.drain(ret);

      return ret;

    } CATCH_ERROR;
    return -1;
  }
#endif // HAVE_OPENSSL

  return buffer.write(fd, length);
}

void TransferWrite::checkFinished() {
  if (!buffer.getLength()) finished = success = true;
}
<|endoftext|>


<commit_before>// Copyright (c) 2016, LAAS-CNRS
// Authors: Joseph Mirabel (joseph.mirabel@laas.fr)
//
// This file is part of hpp-pinocchio.
// hpp-pinocchio is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// hpp-pinocchio is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Lesser Public License for more details.  You should have
// received a copy of the GNU Lesser General Public License along with
// hpp-pinocchio. If not, see <http://www.gnu.org/licenses/>.

#include "hpp/pinocchio/center-of-mass-computation.hh"

#include <algorithm>
#include <boost/foreach.hpp>

#include <pinocchio/algorithm/center-of-mass.hpp>
#include <pinocchio/algorithm/copy.hpp>

#include "hpp/pinocchio/joint.hh"
#include "hpp/pinocchio/device.hh"

#include "center-of-mass-computation/algorithm.cc"

namespace hpp {
  namespace pinocchio {
    CenterOfMassComputationPtr_t CenterOfMassComputation::create (
        const DevicePtr_t& d)
    {
      return CenterOfMassComputationPtr_t (new CenterOfMassComputation (d));
    }

    void CenterOfMassComputation::compute (const Device::Computation_t& flag)
    {
      const Model& model = robot_->model();

      bool computeCOM = (flag & Device::COM);
      bool computeJac = (flag & Device::JACOBIAN);
      assert(computeCOM && "This does nothing");
      assert (!(computeJac && !computeCOM)); // JACOBIAN => COM

      // update kinematics
      se3::copy<0>(model,robot_->data(),data);

      data.mass[0] = 0;
      if(computeCOM) data.com[0].setZero();
      if(computeJac) data.Jcom.setZero();

      // Propagate COM initialization on all joints.
      // Could be done only on subtree, with minor gain (possibly loss because of
      // more difficult branch prediction). I dont recommend to implement it.
      for(JointIndex jid=1;jid<JointIndex(model.joints.size());++jid)
        {
          const double &            mass  = model.inertias[jid].mass ();
          data.mass[jid] = mass;
          data.com [jid] = mass*data.oMi[jid].act (model.inertias[jid].lever());
        }

      // Nullify non-subtree com and mass.
      int root = 0;
      for(JointIndex jid=1; std::size_t(jid)<model.joints.size(); ++jid )
        {
          const JointIndex& rootId = roots_[root];
          if(jid == rootId)
            {
              jid = data.lastChild[rootId];
              root ++;
            }
          else
            {
              data.mass[jid] = 0;
              data.com [jid] .setZero();
            }
        }

      // Assume root is sorted from smallest id.
      // Nasty cast below, from (u-long) size_t to int.
      for( int root=int(roots_.size()-1); root>=0; --root )
      {
        JointIndex rootId = roots_[root];

        // Backward loop on descendents of joint rootId.
        for( JointIndex jid = data.lastChild[rootId];jid>=rootId;--jid )
          {
            if(computeJac)
              se3::JacobianCenterOfMassBackwardStep
                ::run(model.joints[jid],data.joints[jid],
                      se3::JacobianCenterOfMassBackwardStep::ArgsType(model,data,false));
            else
              {
                assert(computeCOM);
                const JointIndex & parent = model.parents[jid];
                data.com [parent] += data.com [jid];
                data.mass[parent] += data.mass[jid];
              }

            //std::cout << data.oMi [jid] << std::endl;
            //std::cout << data.mass[jid] << std::endl;
            //std::cout << data.com [jid].transpose() << std::endl;
          } // end for jid

        // Backward loop on ancestors of joint rootId
        JointIndex jid = model.parents[rootId]; // loop variable
        rootId = (root>0) ? roots_[root-1] : 0;      // root of previous subtree in roots_
        while (jid>rootId)                           // stop when meeting the next subtree
          {
            const JointIndex & parent = model.parents[jid];
            if(computeJac)
              se3::JacobianCenterOfMassBackwardStep
                ::run(model.joints[jid],data.joints[jid],
                      se3::JacobianCenterOfMassBackwardStep::ArgsType(model,data,false));
            else
              {
                assert(computeCOM);
                data.com [parent] += data.com [jid];
                data.mass[parent] += data.mass[jid];
              }
            jid = parent;
          } // end while

      } // end for root in roots_

      if(computeCOM) data.com[0]  /= data.mass[0];
      if(computeJac) data.Jcom    /= data.mass[0];
    }

    CenterOfMassComputation::CenterOfMassComputation (const DevicePtr_t& d) :
      robot_(d), roots_ (), //mass_ (0), jacobianCom_ (3, d->numberDof ())
      data(d->model())
    { assert (d->modelPtr()); }

    void CenterOfMassComputation::add (const JointPtr_t& j)
    {
      JointIndex jid = j->index();
      const Model& model = robot_->model();
      BOOST_FOREACH( const JointIndex rootId,  roots_ )
        {
          assert (std::size_t(rootId)<model.joints.size());
          // Assert that the new root is not in already-recorded subtrees.
          if( (jid<rootId) || (data.lastChild[rootId]<int(jid)) )
            // We are doing something stupid. Should we throw an error
            // or just return silently ?
            throw std::invalid_argument("This joint is already in a subtree");
        }

      roots_.push_back(jid);
    }

    CenterOfMassComputation::~CenterOfMassComputation ()
    {}
  }  //  namespace pinocchio
}  //  namespace hpp
<commit_msg>Fix CenterOfMassComputation::add<commit_after>// Copyright (c) 2016, LAAS-CNRS
// Authors: Joseph Mirabel (joseph.mirabel@laas.fr)
//
// This file is part of hpp-pinocchio.
// hpp-pinocchio is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// hpp-pinocchio is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Lesser Public License for more details.  You should have
// received a copy of the GNU Lesser General Public License along with
// hpp-pinocchio. If not, see <http://www.gnu.org/licenses/>.

#include "hpp/pinocchio/center-of-mass-computation.hh"

#include <algorithm>
#include <boost/foreach.hpp>

#include <pinocchio/algorithm/center-of-mass.hpp>
#include <pinocchio/algorithm/copy.hpp>

#include <hpp/util/exception-factory.hh>

#include "hpp/pinocchio/joint.hh"
#include "hpp/pinocchio/device.hh"

#include "center-of-mass-computation/algorithm.cc"

namespace hpp {
  namespace pinocchio {
    CenterOfMassComputationPtr_t CenterOfMassComputation::create (
        const DevicePtr_t& d)
    {
      return CenterOfMassComputationPtr_t (new CenterOfMassComputation (d));
    }

    void CenterOfMassComputation::compute (const Device::Computation_t& flag)
    {
      const Model& model = robot_->model();

      bool computeCOM = (flag & Device::COM);
      bool computeJac = (flag & Device::JACOBIAN);
      assert(computeCOM && "This does nothing");
      assert (!(computeJac && !computeCOM)); // JACOBIAN => COM

      // update kinematics
      se3::copy<0>(model,robot_->data(),data);

      data.mass[0] = 0;
      if(computeCOM) data.com[0].setZero();
      if(computeJac) data.Jcom.setZero();

      // Propagate COM initialization on all joints.
      // Could be done only on subtree, with minor gain (possibly loss because of
      // more difficult branch prediction). I dont recommend to implement it.
      for(JointIndex jid=1;jid<JointIndex(model.joints.size());++jid)
        {
          const double &            mass  = model.inertias[jid].mass ();
          data.mass[jid] = mass;
          data.com [jid] = mass*data.oMi[jid].act (model.inertias[jid].lever());
        }

      // Nullify non-subtree com and mass.
      int root = 0;
      for(JointIndex jid=1; std::size_t(jid)<model.joints.size(); ++jid )
        {
          const JointIndex& rootId = roots_[root];
          if(jid == rootId)
            {
              jid = data.lastChild[rootId];
              root ++;
            }
          else
            {
              data.mass[jid] = 0;
              data.com [jid] .setZero();
            }
        }

      // Assume root is sorted from smallest id.
      // Nasty cast below, from (u-long) size_t to int.
      for( int root=int(roots_.size()-1); root>=0; --root )
      {
        JointIndex rootId = roots_[root];

        // Backward loop on descendents of joint rootId.
        for( JointIndex jid = data.lastChild[rootId];jid>=rootId;--jid )
          {
            if(computeJac)
              se3::JacobianCenterOfMassBackwardStep
                ::run(model.joints[jid],data.joints[jid],
                      se3::JacobianCenterOfMassBackwardStep::ArgsType(model,data,false));
            else
              {
                assert(computeCOM);
                const JointIndex & parent = model.parents[jid];
                data.com [parent] += data.com [jid];
                data.mass[parent] += data.mass[jid];
              }

            //std::cout << data.oMi [jid] << std::endl;
            //std::cout << data.mass[jid] << std::endl;
            //std::cout << data.com [jid].transpose() << std::endl;
          } // end for jid

        // Backward loop on ancestors of joint rootId
        JointIndex jid = model.parents[rootId]; // loop variable
        rootId = (root>0) ? roots_[root-1] : 0;      // root of previous subtree in roots_
        while (jid>rootId)                           // stop when meeting the next subtree
          {
            const JointIndex & parent = model.parents[jid];
            if(computeJac)
              se3::JacobianCenterOfMassBackwardStep
                ::run(model.joints[jid],data.joints[jid],
                      se3::JacobianCenterOfMassBackwardStep::ArgsType(model,data,false));
            else
              {
                assert(computeCOM);
                data.com [parent] += data.com [jid];
                data.mass[parent] += data.mass[jid];
              }
            jid = parent;
          } // end while

      } // end for root in roots_

      if(computeCOM) data.com[0]  /= data.mass[0];
      if(computeJac) data.Jcom    /= data.mass[0];
    }

    CenterOfMassComputation::CenterOfMassComputation (const DevicePtr_t& d) :
      robot_(d), roots_ (), //mass_ (0), jacobianCom_ (3, d->numberDof ())
      data(d->model())
    { assert (d->modelPtr()); }

    void CenterOfMassComputation::add (const JointPtr_t& j)
    {
      JointIndex jid = j->index();
      const Model& model = robot_->model();
      BOOST_FOREACH( const JointIndex rootId,  roots_ )
        {
          assert (std::size_t(rootId)<model.joints.size());
          // Assert that the new root is not in already-recorded subtrees.
          if( (jid >= rootId) && (data.lastChild[rootId] >= int(jid)) )
            // We are doing something stupid. Should we throw an error
            // or just return silently ?
            HPP_THROW(std::invalid_argument, "Joint " << j->name()
                << " (" << jid << ") is already in a subtree ["
                << rootId << ", " << data.lastChild[rootId] << "]");
        }

      roots_.push_back(jid);
    }

    CenterOfMassComputation::~CenterOfMassComputation ()
    {}
  }  //  namespace pinocchio
}  //  namespace hpp
<|endoftext|>


<commit_before>
#include "../cpp-utility/os.hpp"
#include "../dependencies/catch.hpp"

#include "testlib.hpp"

TEST_CASE( "only_interface" )
{
    // This isn't really a runtime test.
    // If the types are not exported, this should fail to compile at all.
    SECTION( "Types are exported" )
    {
        IOnlyInterface_Automation* pAutomation = nullptr;
        IOnlyInterface_Raw* pRaw = nullptr;
    }

    // We could just as well use this to ensure the auto-generated guids don't
    // change.
    SECTION( "GUIDs remain constant" )
    {
        GUID automation = { 0xfe0b0f3a, 0x7710, 0x3e69, 0x48, 0x6b, 0xd6, 0x01, 0x6b, 0xd8, 0xf8, 0x9d };
        GUID raw = { 0xe7de960d, 0x26be, 0x31fa, 0x5c, 0x98, 0x63, 0x0e, 0x66, 0xcc, 0x22, 0x7d };
        REQUIRE( IID_IOnlyInterface_Automation == automation );
        REQUIRE( IID_IOnlyInterface_Raw == raw );
    }
}
<commit_msg>Make types cross platform<commit_after>
#include "../cpp-utility/os.hpp"
#include "../dependencies/catch.hpp"

#include "testlib.hpp"

TEST_CASE( "only_interface" )
{
    // This isn't really a runtime test.
    // If the types are not exported, this should fail to compile at all.
    SECTION( "Types are exported" )
    {
        IOnlyInterface_Automation* pAutomation = nullptr;
        IOnlyInterface_Raw* pRaw = nullptr;
    }

    // We could just as well use this to ensure the auto-generated guids don't
    // change.
    SECTION( "GUIDs remain constant" )
    {
        intercom::IID automation = { 0xfe0b0f3a, 0x7710, 0x3e69, 0x48, 0x6b, 0xd6, 0x01, 0x6b, 0xd8, 0xf8, 0x9d };
        intercom::IID raw = { 0xe7de960d, 0x26be, 0x31fa, 0x5c, 0x98, 0x63, 0x0e, 0x66, 0xcc, 0x22, 0x7d };
        REQUIRE( IID_IOnlyInterface_Automation == automation );
        REQUIRE( IID_IOnlyInterface_Raw == raw );
    }
}
<|endoftext|>


<commit_before>#include <type_traits>
#include <gtest/gtest.h>
#include <entt/core/hashed_string.hpp>
#include <entt/core/type_info.hpp>
#include <entt/resource/cache.hpp>

struct resource {
    virtual const entt::type_info &type() const ENTT_NOEXCEPT {
        return entt::type_id<resource>();
    }

    int value;
};

struct derived_resource: resource {
    const entt::type_info &type() const ENTT_NOEXCEPT override {
        return entt::type_id<derived_resource>();
    }
};

template<typename Resource>
struct loader: entt::resource_loader<loader<Resource>, Resource> {
    std::shared_ptr<Resource> load(int value) const {
        auto res = std::shared_ptr<Resource>(new Resource);
        res->value = value;
        return res;
    }
};

template<typename Resource>
struct broken_loader: entt::resource_loader<broken_loader<Resource>, Resource> {
    std::shared_ptr<Resource> load(int) const {
        return nullptr;
    }
};

template<typename Type, typename Other>
entt::resource_handle<Type> dynamic_resource_handle_cast(const entt::resource_handle<Other> &other) {
    if(other->type() == entt::type_id<Type>()) {
        return entt::resource_handle<Type>{other, static_cast<Type &>(other.get())};
    }

    return {};
}

TEST(Resource, Functionalities) {
    entt::resource_cache<resource> cache;

    constexpr auto hs1 = entt::hashed_string{"res1"};
    constexpr auto hs2 = entt::hashed_string{"res2"};

    ASSERT_EQ(cache.size(), 0u);
    ASSERT_TRUE(cache.empty());
    ASSERT_FALSE(cache.contains(hs1));
    ASSERT_FALSE(cache.contains(hs2));

    ASSERT_FALSE(cache.load<broken_loader<resource>>(hs1, 42));
    ASSERT_FALSE(cache.reload<broken_loader<resource>>(hs1, 42));

    ASSERT_EQ(cache.size(), 0u);
    ASSERT_TRUE(cache.empty());
    ASSERT_FALSE(cache.contains(hs1));
    ASSERT_FALSE(cache.contains(hs2));

    ASSERT_TRUE(cache.load<loader<resource>>(hs1, 42));
    ASSERT_TRUE(cache.reload<loader<resource>>(hs1, 42));

    ASSERT_EQ(cache.handle(hs1).use_count(), 2);

    auto tmp = cache.handle(hs1);

    ASSERT_EQ(std::as_const(cache).handle(hs1).use_count(), 3);
    ASSERT_TRUE(static_cast<bool>(tmp));

    tmp = {};

    ASSERT_EQ(cache.handle(hs1).use_count(), 2);
    ASSERT_FALSE(static_cast<bool>(tmp));

    ASSERT_NE(cache.size(), 0u);
    ASSERT_FALSE(cache.empty());
    ASSERT_TRUE(cache.contains(hs1));
    ASSERT_FALSE(cache.contains(hs2));
    ASSERT_EQ((*std::as_const(cache).handle(hs1)).value, 42);

    ASSERT_TRUE(cache.load<loader<resource>>(hs1, 42));
    ASSERT_TRUE(cache.load<loader<resource>>(hs2, 42));

    ASSERT_NE(cache.size(), 0u);
    ASSERT_FALSE(cache.empty());
    ASSERT_TRUE(cache.contains(hs1));
    ASSERT_TRUE(cache.contains(hs2));
    ASSERT_EQ((*cache.handle(hs1)).value, 42);
    ASSERT_EQ(std::as_const(cache).handle(hs2)->value, 42);

    ASSERT_NO_FATAL_FAILURE(cache.discard(hs1));

    ASSERT_FALSE(cache.contains(hs1));
    ASSERT_TRUE(cache.contains(hs2));
    ASSERT_EQ(cache.handle(hs2)->value, 42);

    ASSERT_TRUE(cache.load<loader<resource>>(hs1, 42));
    ASSERT_NO_FATAL_FAILURE(cache.clear());

    ASSERT_EQ(cache.size(), 0u);
    ASSERT_TRUE(cache.empty());
    ASSERT_FALSE(cache.contains(hs1));
    ASSERT_FALSE(cache.contains(hs2));

    ASSERT_TRUE(cache.load<loader<resource>>(hs1, 42));

    ASSERT_NE(cache.size(), 0u);
    ASSERT_FALSE(cache.empty());
    ASSERT_TRUE(cache.handle(hs1));
    ASSERT_FALSE(cache.handle(hs2));
    ASSERT_TRUE(std::as_const(cache).handle(hs1));
    ASSERT_FALSE(std::as_const(cache).handle(hs2));

    ASSERT_TRUE(std::as_const(cache).handle(hs1));
    ASSERT_EQ(&cache.handle(hs1).get(), &static_cast<const resource &>(cache.handle(hs1)));
    ASSERT_NO_FATAL_FAILURE(cache.clear());

    ASSERT_EQ(cache.size(), 0u);
    ASSERT_TRUE(cache.empty());

    ASSERT_TRUE(cache.temp<loader<resource>>(42));
    ASSERT_TRUE(cache.empty());

    ASSERT_FALSE(entt::resource_handle<resource>{});
    ASSERT_TRUE(std::is_copy_constructible_v<entt::resource_handle<resource>>);
    ASSERT_TRUE(std::is_move_constructible_v<entt::resource_handle<resource>>);
    ASSERT_TRUE(std::is_copy_assignable_v<entt::resource_handle<resource>>);
    ASSERT_TRUE(std::is_move_assignable_v<entt::resource_handle<resource>>);
}

TEST(Resource, ConstNonConstHandle) {
    entt::resource_cache<resource> cache;

    entt::resource_handle<resource> handle = cache.temp<loader<resource>>(42);
    entt::resource_handle<const resource> chandle = handle;

    static_assert(std::is_same_v<decltype(handle.get()), resource &>);
    static_assert(std::is_same_v<decltype(chandle.get()), const resource &>);
    static_assert(std::is_same_v<decltype(std::as_const(handle).get()), resource &>);

    ASSERT_TRUE(chandle);
    ASSERT_EQ(handle.use_count(), 2u);
    ASSERT_EQ(chandle->value, 42);

    chandle = {};

    ASSERT_FALSE(chandle);
    ASSERT_EQ(handle.use_count(), 1u);
}

TEST(Resource, MutableHandle) {
    entt::resource_cache<resource> cache;

    constexpr auto hs = entt::hashed_string{"res"};
    auto handle = cache.load<loader<resource>>(hs, 0);

    ASSERT_TRUE(handle);

    ++handle.get().value;
    ++static_cast<resource &>(handle).value;
    ++(*handle).value;
    ++handle->value;

    ASSERT_EQ(cache.handle(hs)->value, 4);
}

TEST(Resource, HandleImplicitCast) {
    entt::resource_cache<resource> cache;
    auto handle = cache.temp<loader<derived_resource>>(0);

    auto resource = std::make_shared<derived_resource>();
    entt::resource_handle<derived_resource> other{resource};

    ASSERT_TRUE(handle);
    ASSERT_TRUE(other);
    ASSERT_NE(&*handle, &*other);
    ASSERT_EQ(resource.use_count(), 2u);

    auto temp = std::move(handle);
    handle = other;

    ASSERT_TRUE(handle);
    ASSERT_TRUE(other);
    ASSERT_TRUE(temp);
    ASSERT_EQ(&*handle, &*other);
    ASSERT_EQ(resource.use_count(), 3u);

    temp = std::move(other);

    ASSERT_TRUE(handle);
    ASSERT_FALSE(other);
    ASSERT_TRUE(temp);
    ASSERT_EQ(&*handle, &*temp);
    ASSERT_EQ(resource.use_count(), 3u);

    temp = handle = {};

    ASSERT_FALSE(handle);
    ASSERT_FALSE(other);
    ASSERT_FALSE(temp);
    ASSERT_EQ(resource.use_count(), 1u);
}

TEST(Resource, DynamicResourceHandleCast) {
    entt::resource_handle<derived_resource> handle = entt::resource_cache<derived_resource>{}.temp<loader<derived_resource>>(42);
    entt::resource_handle<const resource> base = handle;

    ASSERT_TRUE(base);
    ASSERT_EQ(handle.use_count(), 2u);
    ASSERT_EQ(base->value, 42);

    entt::resource_handle<const derived_resource> chandle = dynamic_resource_handle_cast<const derived_resource>(base);

    ASSERT_TRUE(chandle);
    ASSERT_EQ(handle.use_count(), 3u);
    ASSERT_EQ(chandle->value, 42);

    base = entt::resource_cache<resource>{}.temp<loader<resource>>(42);
    chandle = dynamic_resource_handle_cast<const derived_resource>(base);

    ASSERT_FALSE(chandle);
    ASSERT_EQ(handle.use_count(), 1u);
}

TEST(Resource, Each) {
    using namespace entt::literals;

    entt::resource_cache<resource> cache;
    cache.load<loader<resource>>("resource"_hs, 0);

    cache.each([](entt::resource_handle<resource> res) {
        ++res->value;
    });

    ASSERT_FALSE(cache.empty());
    ASSERT_EQ(cache.handle("resource"_hs)->value, 1);

    cache.each([](entt::id_type id, entt::resource_handle<resource> res) {
        ASSERT_EQ(id, "resource"_hs);
        ++res->value;
    });

    ASSERT_FALSE(cache.empty());

    std::as_const(cache).each([](entt::id_type id, entt::resource_handle<const resource> res) {
        ASSERT_EQ(res->value, 2);
    });

    cache.each([&cache](entt::id_type id) {
        cache.discard(id);
    });

    ASSERT_TRUE(cache.empty());
}
<commit_msg>test: suppress warnings due to missing virtual destructor<commit_after>#include <type_traits>
#include <gtest/gtest.h>
#include <entt/core/hashed_string.hpp>
#include <entt/core/type_info.hpp>
#include <entt/resource/cache.hpp>

struct resource {
    virtual ~resource() = default;

    virtual const entt::type_info &type() const ENTT_NOEXCEPT {
        return entt::type_id<resource>();
    }

    int value;
};

struct derived_resource: resource {
    const entt::type_info &type() const ENTT_NOEXCEPT override {
        return entt::type_id<derived_resource>();
    }
};

template<typename Resource>
struct loader: entt::resource_loader<loader<Resource>, Resource> {
    std::shared_ptr<Resource> load(int value) const {
        auto res = std::shared_ptr<Resource>(new Resource);
        res->value = value;
        return res;
    }
};

template<typename Resource>
struct broken_loader: entt::resource_loader<broken_loader<Resource>, Resource> {
    std::shared_ptr<Resource> load(int) const {
        return nullptr;
    }
};

template<typename Type, typename Other>
entt::resource_handle<Type> dynamic_resource_handle_cast(const entt::resource_handle<Other> &other) {
    if(other->type() == entt::type_id<Type>()) {
        return entt::resource_handle<Type>{other, static_cast<Type &>(other.get())};
    }

    return {};
}

TEST(Resource, Functionalities) {
    entt::resource_cache<resource> cache;

    constexpr auto hs1 = entt::hashed_string{"res1"};
    constexpr auto hs2 = entt::hashed_string{"res2"};

    ASSERT_EQ(cache.size(), 0u);
    ASSERT_TRUE(cache.empty());
    ASSERT_FALSE(cache.contains(hs1));
    ASSERT_FALSE(cache.contains(hs2));

    ASSERT_FALSE(cache.load<broken_loader<resource>>(hs1, 42));
    ASSERT_FALSE(cache.reload<broken_loader<resource>>(hs1, 42));

    ASSERT_EQ(cache.size(), 0u);
    ASSERT_TRUE(cache.empty());
    ASSERT_FALSE(cache.contains(hs1));
    ASSERT_FALSE(cache.contains(hs2));

    ASSERT_TRUE(cache.load<loader<resource>>(hs1, 42));
    ASSERT_TRUE(cache.reload<loader<resource>>(hs1, 42));

    ASSERT_EQ(cache.handle(hs1).use_count(), 2);

    auto tmp = cache.handle(hs1);

    ASSERT_EQ(std::as_const(cache).handle(hs1).use_count(), 3);
    ASSERT_TRUE(static_cast<bool>(tmp));

    tmp = {};

    ASSERT_EQ(cache.handle(hs1).use_count(), 2);
    ASSERT_FALSE(static_cast<bool>(tmp));

    ASSERT_NE(cache.size(), 0u);
    ASSERT_FALSE(cache.empty());
    ASSERT_TRUE(cache.contains(hs1));
    ASSERT_FALSE(cache.contains(hs2));
    ASSERT_EQ((*std::as_const(cache).handle(hs1)).value, 42);

    ASSERT_TRUE(cache.load<loader<resource>>(hs1, 42));
    ASSERT_TRUE(cache.load<loader<resource>>(hs2, 42));

    ASSERT_NE(cache.size(), 0u);
    ASSERT_FALSE(cache.empty());
    ASSERT_TRUE(cache.contains(hs1));
    ASSERT_TRUE(cache.contains(hs2));
    ASSERT_EQ((*cache.handle(hs1)).value, 42);
    ASSERT_EQ(std::as_const(cache).handle(hs2)->value, 42);

    ASSERT_NO_FATAL_FAILURE(cache.discard(hs1));

    ASSERT_FALSE(cache.contains(hs1));
    ASSERT_TRUE(cache.contains(hs2));
    ASSERT_EQ(cache.handle(hs2)->value, 42);

    ASSERT_TRUE(cache.load<loader<resource>>(hs1, 42));
    ASSERT_NO_FATAL_FAILURE(cache.clear());

    ASSERT_EQ(cache.size(), 0u);
    ASSERT_TRUE(cache.empty());
    ASSERT_FALSE(cache.contains(hs1));
    ASSERT_FALSE(cache.contains(hs2));

    ASSERT_TRUE(cache.load<loader<resource>>(hs1, 42));

    ASSERT_NE(cache.size(), 0u);
    ASSERT_FALSE(cache.empty());
    ASSERT_TRUE(cache.handle(hs1));
    ASSERT_FALSE(cache.handle(hs2));
    ASSERT_TRUE(std::as_const(cache).handle(hs1));
    ASSERT_FALSE(std::as_const(cache).handle(hs2));

    ASSERT_TRUE(std::as_const(cache).handle(hs1));
    ASSERT_EQ(&cache.handle(hs1).get(), &static_cast<const resource &>(cache.handle(hs1)));
    ASSERT_NO_FATAL_FAILURE(cache.clear());

    ASSERT_EQ(cache.size(), 0u);
    ASSERT_TRUE(cache.empty());

    ASSERT_TRUE(cache.temp<loader<resource>>(42));
    ASSERT_TRUE(cache.empty());

    ASSERT_FALSE(entt::resource_handle<resource>{});
    ASSERT_TRUE(std::is_copy_constructible_v<entt::resource_handle<resource>>);
    ASSERT_TRUE(std::is_move_constructible_v<entt::resource_handle<resource>>);
    ASSERT_TRUE(std::is_copy_assignable_v<entt::resource_handle<resource>>);
    ASSERT_TRUE(std::is_move_assignable_v<entt::resource_handle<resource>>);
}

TEST(Resource, ConstNonConstHandle) {
    entt::resource_cache<resource> cache;

    entt::resource_handle<resource> handle = cache.temp<loader<resource>>(42);
    entt::resource_handle<const resource> chandle = handle;

    static_assert(std::is_same_v<decltype(handle.get()), resource &>);
    static_assert(std::is_same_v<decltype(chandle.get()), const resource &>);
    static_assert(std::is_same_v<decltype(std::as_const(handle).get()), resource &>);

    ASSERT_TRUE(chandle);
    ASSERT_EQ(handle.use_count(), 2u);
    ASSERT_EQ(chandle->value, 42);

    chandle = {};

    ASSERT_FALSE(chandle);
    ASSERT_EQ(handle.use_count(), 1u);
}

TEST(Resource, MutableHandle) {
    entt::resource_cache<resource> cache;

    constexpr auto hs = entt::hashed_string{"res"};
    auto handle = cache.load<loader<resource>>(hs, 0);

    ASSERT_TRUE(handle);

    ++handle.get().value;
    ++static_cast<resource &>(handle).value;
    ++(*handle).value;
    ++handle->value;

    ASSERT_EQ(cache.handle(hs)->value, 4);
}

TEST(Resource, HandleImplicitCast) {
    entt::resource_cache<resource> cache;
    auto handle = cache.temp<loader<derived_resource>>(0);

    auto resource = std::make_shared<derived_resource>();
    entt::resource_handle<derived_resource> other{resource};

    ASSERT_TRUE(handle);
    ASSERT_TRUE(other);
    ASSERT_NE(&*handle, &*other);
    ASSERT_EQ(resource.use_count(), 2u);

    auto temp = std::move(handle);
    handle = other;

    ASSERT_TRUE(handle);
    ASSERT_TRUE(other);
    ASSERT_TRUE(temp);
    ASSERT_EQ(&*handle, &*other);
    ASSERT_EQ(resource.use_count(), 3u);

    temp = std::move(other);

    ASSERT_TRUE(handle);
    ASSERT_FALSE(other);
    ASSERT_TRUE(temp);
    ASSERT_EQ(&*handle, &*temp);
    ASSERT_EQ(resource.use_count(), 3u);

    temp = handle = {};

    ASSERT_FALSE(handle);
    ASSERT_FALSE(other);
    ASSERT_FALSE(temp);
    ASSERT_EQ(resource.use_count(), 1u);
}

TEST(Resource, DynamicResourceHandleCast) {
    entt::resource_handle<derived_resource> handle = entt::resource_cache<derived_resource>{}.temp<loader<derived_resource>>(42);
    entt::resource_handle<const resource> base = handle;

    ASSERT_TRUE(base);
    ASSERT_EQ(handle.use_count(), 2u);
    ASSERT_EQ(base->value, 42);

    entt::resource_handle<const derived_resource> chandle = dynamic_resource_handle_cast<const derived_resource>(base);

    ASSERT_TRUE(chandle);
    ASSERT_EQ(handle.use_count(), 3u);
    ASSERT_EQ(chandle->value, 42);

    base = entt::resource_cache<resource>{}.temp<loader<resource>>(42);
    chandle = dynamic_resource_handle_cast<const derived_resource>(base);

    ASSERT_FALSE(chandle);
    ASSERT_EQ(handle.use_count(), 1u);
}

TEST(Resource, Each) {
    using namespace entt::literals;

    entt::resource_cache<resource> cache;
    cache.load<loader<resource>>("resource"_hs, 0);

    cache.each([](entt::resource_handle<resource> res) {
        ++res->value;
    });

    ASSERT_FALSE(cache.empty());
    ASSERT_EQ(cache.handle("resource"_hs)->value, 1);

    cache.each([](entt::id_type id, entt::resource_handle<resource> res) {
        ASSERT_EQ(id, "resource"_hs);
        ++res->value;
    });

    ASSERT_FALSE(cache.empty());

    std::as_const(cache).each([](entt::id_type id, entt::resource_handle<const resource> res) {
        ASSERT_EQ(res->value, 2);
    });

    cache.each([&cache](entt::id_type id) {
        cache.discard(id);
    });

    ASSERT_TRUE(cache.empty());
}
<|endoftext|>


<commit_before>/*
 * Read bytecode from a file, run it and print the result (top of the stack)
 */
#include "all_defines.hpp"

#include <iostream>
#include <fstream>

#include "reader.hpp"
#include "executors.hpp"
#include "symbols.hpp"

using namespace std;

void throw_HlError(const char *str) {
  cout << "Error: " << str << endl << flush;
  exit(1);
}

void throw_OverBrokenHeart(Generic*) {
  throw_HlError("overbrokenheart");
}

/*
 * printing
 */
ostream& operator<<(ostream & o, Object::ref r) {
  if (is_a<int>(r)) {
    o << as_a<int>(r);
  } else {
    o << "#<unknown type>";
  }
  return o;
}

int main(int argc, char **argv) {
  if (argc!=2) {
    cout << "Wrong number of arguments" << endl;
    return 1;
  }

  ifstream in(argv[1]);
  if (!in) {
    cout << "Can't open file: " << argv[1] << endl;
    return 2;
  }

  boost::scoped_ptr<SymbolsTable> syms(new SymbolsTable);
  symbols.swap(syms);

  BytecodeSeq program;
  try {
    while (!in.eof())
      in >> program;
  } catch (ReadError e) {
    cout << "Reader error: " << e << endl;
    exit(-1);
  }

  bytecode_t *to_run;
  Process p;
  Process* Q;
  size_t timeslice;
  timeslice = 128;
  execute(p, timeslice, Q, 1); // init phase
  assemble(program, to_run);
  p.stack.push(Object::to_ref(Closure::NewKClosure(p, to_run, 0))); // entry point
  timeslice = 128;
  execute(p, timeslice, Q); // run!

  Object::ref res = p.stack.top();
  if (is_a<int>(res))
    cout << as_a<int>(res) << endl;
  else {
    if (is_a<Symbol*>(res))
      cout << as_a<Symbol*>(res)->getPrintName() << endl;
    else {
      if (is_a<Generic*>(res)) {
        Float *f;
        if ((f = dynamic_cast<Float*>(as_a<Generic*>(res)))!=NULL)
          cout << f->get() << endl;
        else
          cout << "#<unknown type>" << endl;
      }
    }
  }

  return 0;
}
<commit_msg>test/executors/run_bytecode.cpp: Added header for exit()<commit_after>/*
 * Read bytecode from a file, run it and print the result (top of the stack)
 */
#include "all_defines.hpp"

#include <iostream>
#include <fstream>
#include <cstdlib>

#include "reader.hpp"
#include "executors.hpp"
#include "symbols.hpp"

using namespace std;

void throw_HlError(const char *str) {
  cout << "Error: " << str << endl << flush;
  exit(1);
}

void throw_OverBrokenHeart(Generic*) {
  throw_HlError("overbrokenheart");
}

/*
 * printing
 */
ostream& operator<<(ostream & o, Object::ref r) {
  if (is_a<int>(r)) {
    o << as_a<int>(r);
  } else {
    o << "#<unknown type>";
  }
  return o;
}

int main(int argc, char **argv) {
  if (argc!=2) {
    cout << "Wrong number of arguments" << endl;
    return 1;
  }

  ifstream in(argv[1]);
  if (!in) {
    cout << "Can't open file: " << argv[1] << endl;
    return 2;
  }

  boost::scoped_ptr<SymbolsTable> syms(new SymbolsTable);
  symbols.swap(syms);

  BytecodeSeq program;
  try {
    while (!in.eof())
      in >> program;
  } catch (ReadError e) {
    cout << "Reader error: " << e << endl;
    exit(-1);
  }

  bytecode_t *to_run;
  Process p;
  Process* Q;
  size_t timeslice;
  timeslice = 128;
  execute(p, timeslice, Q, 1); // init phase
  assemble(program, to_run);
  p.stack.push(Object::to_ref(Closure::NewKClosure(p, to_run, 0))); // entry point
  timeslice = 128;
  execute(p, timeslice, Q); // run!

  Object::ref res = p.stack.top();
  if (is_a<int>(res))
    cout << as_a<int>(res) << endl;
  else {
    if (is_a<Symbol*>(res))
      cout << as_a<Symbol*>(res)->getPrintName() << endl;
    else {
      if (is_a<Generic*>(res)) {
        Float *f;
        if ((f = dynamic_cast<Float*>(as_a<Generic*>(res)))!=NULL)
          cout << f->get() << endl;
        else
          cout << "#<unknown type>" << endl;
      }
    }
  }

  return 0;
}
<|endoftext|>


<commit_before>/* comploader.cpp
   Copyright (C) 2003-2005 Tommi Maekitalo

This file is part of tntnet.

Tntnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

Tntnet is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with tntnet; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA  02111-1307  USA
*/

#include <tnt/comploader.h>
#include <tnt/componentfactory.h>
#include <tnt/tntconfig.h>
#include <cxxtools/log.h>

namespace tnt
{

////////////////////////////////////////////////////////////////////////
// ComponentLibrary
//
log_define("tntnet.comploader")

Component* ComponentLibrary::create(
  const std::string& component_name, Comploader& cl,
  const Urlmapper& rootmapper)
{
  log_debug("create \"" << component_name << '"');

  ComponentFactory* factory;

  // look for factory in my map
  factoryMapType::const_iterator i = factoryMap.find(component_name);
  if (i == factoryMap.end())
  {
    std::string factoryName = component_name + "_factory";
    if (getHandle() == 0)
      throw cxxtools::dl::SymbolNotFound(factoryName);

    // creatorsymbol not known - load it
    log_debug("lookup symbol \"" << factoryName << '"');

    factory = static_cast<ComponentFactory*>(sym(factoryName.c_str()).getSym());
    factoryMap.insert(factoryMapType::value_type(component_name, factory));
  }
  else
    factory = i->second;

  // call the creator
  Compident ci = Compident(libname, component_name);
  log_info("create \"" << ci << '"');

  return factory->create(ci, rootmapper, cl);
}

////////////////////////////////////////////////////////////////////////
// Comploader
//
Comploader::Comploader()
{
  if (config)
  {
    Tntconfig::config_entries_type configLoad;
    config->getConfigValues("Load", configLoad);

    for (Tntconfig::config_entries_type::const_iterator it = configLoad.begin();
         it != configLoad.end(); ++it)
    {
      if (it->params.empty())
        throw std::runtime_error("missing libraryname in Load-command");
      fetchLib(it->params[0]);
    }
  }
}

Comploader::~Comploader()
{
  for (componentmap_type::iterator i = componentmap.begin();
       i != componentmap.end(); ++i)
  {
    log_debug("drop " << i->first << " (" << i->second << ')');
    i->second->drop();
  }
}

cxxtools::RWLock Comploader::libraryMonitor;
Comploader::librarymap_type Comploader::librarymap;
const Tntconfig* Comploader::config = 0;
Comploader::search_path_type Comploader::search_path;
bool Comploader::staticFactoryAddEnabled = true;

Component& Comploader::fetchComp(const Compident& ci,
  const Urlmapper& rootmapper)
{
  log_debug("fetchComp \"" << ci << '"');

  cxxtools::RdLock lock(componentMonitor);

  // lookup Component
  componentmap_type::iterator it = componentmap.find(ci);
  if (it == componentmap.end())
  {
    // Component not known - lookup shared lib, fetch creator and create a new
    // Component
    lock.unlock();

    cxxtools::WrLock wrlock(componentMonitor);

    // doublecheck after getting writelock
    it = componentmap.find(ci);
    if (it == componentmap.end())
    {
      ComponentLibrary& lib = fetchLib(ci.libname);
      Component* comp = lib.create(ci.compname, *this, rootmapper);

      componentmap[ci] = comp;
      comp->touch();
      return *comp;
    }
    else
    {
      it->second->touch();
      return *(it->second);
    }
  }
  else
  {
    it->second->touch();
    return *(it->second);
  }
}

Component* Comploader::createComp(const Compident& ci,
  const Urlmapper& rootmapper)
{
  log_debug("createComp \"" << ci << '"');

  ComponentLibrary& lib = fetchLib(ci.libname);
  Component* comp = lib.create(ci.compname, *this, rootmapper);
  comp->touch();
  return comp;
}

ComponentLibrary& Comploader::fetchLib(const std::string& libname)
{
  log_debug("fetchLib \"" << libname << '"');

  // When first library is fetched static initializers are run,
  // so we disable registation of static factories here.
  staticFactoryAddEnabled = false;

  cxxtools::RdLock lock(libraryMonitor);
  librarymap_type::iterator it = librarymap.find(libname);
  if (it == librarymap.end())
  {
    lock.unlock();

    cxxtools::WrLock wrlock(libraryMonitor);

    // doublecheck after writelock
    it = librarymap.find(libname);
    if (it == librarymap.end())
    {
      // load library
      log_info("load library \"" << libname << '"');
      ComponentLibrary lib;

      bool found = false;
      for (search_path_type::const_iterator p = search_path.begin();
           p != search_path.end(); ++p)
      {
        try
        {
          log_debug("load library \"" << libname << "\" from " << *p << " dir");
          lib = ComponentLibrary(*p, libname);
          found = true;
          break;
        }
        catch (const cxxtools::dl::DlopenError&)
        {
        }
      }

      if (!found)
      {
        try
        {
          log_debug("load library \"" << libname << "\" from current dir");
          lib = ComponentLibrary(".", libname);
        }
        catch (const cxxtools::dl::DlopenError& e)
        {
          log_debug("library \"" << e.getLibname() << "\" in current dir not found - search lib-path");
          lib = ComponentLibrary(libname);
        }
      }

      it = librarymap.insert(librarymap_type::value_type(libname, lib)).first;
    }
  }

  return it->second;
}

void Comploader::cleanup(unsigned seconds)
{
  time_t t = time(0) - seconds;

  cxxtools::RdLock rdlock(componentMonitor);
  for (componentmap_type::iterator it = componentmap.begin();
       it != componentmap.end(); ++it)
  {
    if (it->second->getLastAccesstime() < t)
    {
      // we have something to clean
      rdlock.unlock();

      cxxtools::WrLock wrlock(componentMonitor);
      it = componentmap.begin();
      while (it != componentmap.end())
      {
        if (it->second->getLastAccesstime() < t)
        {
          componentmap_type::iterator it2 = it;
          ++it;
          log_debug("drop " << it2->first);
          it2->second->drop();
          componentmap.erase(it2);
        }
      else
        ++it;
      }
      break;
    }
  }
}

void Comploader::configure(const Tntconfig& config_)
{
  config = &config_;

  Tntconfig::config_entries_type compPath;
  config_.getConfigValues("CompPath", compPath);
  for (Tntconfig::config_entries_type::const_iterator it = compPath.begin();
       it != compPath.end(); ++it)
  {
    if (it->params.size() > 0)
      search_path.push_back(it->params[0]);
  }
}

void Comploader::addStaticFactory(const std::string& component_name,
  ComponentFactory* factory)
{
  std::cout << "addStaticFactory " << component_name << std::endl;
  if (staticFactoryAddEnabled)
  {
    log_debug("Comploader::addStaticFactory(" << component_name << ", "
      << factory << ')');

    // seach library with empty name

    cxxtools::WrLock wrlock(libraryMonitor);
    librarymap_type::iterator it = librarymap.find(std::string());
    if (it == librarymap.end())
    {
      // empty library not in map - create a new empty library-object
      it = librarymap.insert(
        librarymap_type::value_type(std::string(),
                                    ComponentLibrary())).first;
    }
    it->second.addStaticFactory(component_name, factory);
  }
}

}
<commit_msg>don't log with log_info<commit_after>/* comploader.cpp
   Copyright (C) 2003-2005 Tommi Maekitalo

This file is part of tntnet.

Tntnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

Tntnet is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with tntnet; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA  02111-1307  USA
*/

#include <tnt/comploader.h>
#include <tnt/componentfactory.h>
#include <tnt/tntconfig.h>
#include <cxxtools/log.h>

namespace tnt
{

////////////////////////////////////////////////////////////////////////
// ComponentLibrary
//
log_define("tntnet.comploader")

Component* ComponentLibrary::create(
  const std::string& component_name, Comploader& cl,
  const Urlmapper& rootmapper)
{
  log_debug("create \"" << component_name << '"');

  ComponentFactory* factory;

  // look for factory in my map
  factoryMapType::const_iterator i = factoryMap.find(component_name);
  if (i == factoryMap.end())
  {
    std::string factoryName = component_name + "_factory";
    if (getHandle() == 0)
      throw cxxtools::dl::SymbolNotFound(factoryName);

    // creatorsymbol not known - load it
    log_debug("lookup symbol \"" << factoryName << '"');

    factory = static_cast<ComponentFactory*>(sym(factoryName.c_str()).getSym());
    factoryMap.insert(factoryMapType::value_type(component_name, factory));
  }
  else
    factory = i->second;

  // call the creator
  Compident ci = Compident(libname, component_name);
  log_debug("create \"" << ci << '"');

  return factory->create(ci, rootmapper, cl);
}

////////////////////////////////////////////////////////////////////////
// Comploader
//
Comploader::Comploader()
{
  if (config)
  {
    Tntconfig::config_entries_type configLoad;
    config->getConfigValues("Load", configLoad);

    for (Tntconfig::config_entries_type::const_iterator it = configLoad.begin();
         it != configLoad.end(); ++it)
    {
      if (it->params.empty())
        throw std::runtime_error("missing libraryname in Load-command");
      fetchLib(it->params[0]);
    }
  }
}

Comploader::~Comploader()
{
  for (componentmap_type::iterator i = componentmap.begin();
       i != componentmap.end(); ++i)
  {
    log_debug("drop " << i->first << " (" << i->second << ')');
    i->second->drop();
  }
}

cxxtools::RWLock Comploader::libraryMonitor;
Comploader::librarymap_type Comploader::librarymap;
const Tntconfig* Comploader::config = 0;
Comploader::search_path_type Comploader::search_path;
bool Comploader::staticFactoryAddEnabled = true;

Component& Comploader::fetchComp(const Compident& ci,
  const Urlmapper& rootmapper)
{
  log_debug("fetchComp \"" << ci << '"');

  cxxtools::RdLock lock(componentMonitor);

  // lookup Component
  componentmap_type::iterator it = componentmap.find(ci);
  if (it == componentmap.end())
  {
    // Component not known - lookup shared lib, fetch creator and create a new
    // Component
    lock.unlock();

    cxxtools::WrLock wrlock(componentMonitor);

    // doublecheck after getting writelock
    it = componentmap.find(ci);
    if (it == componentmap.end())
    {
      ComponentLibrary& lib = fetchLib(ci.libname);
      Component* comp = lib.create(ci.compname, *this, rootmapper);

      componentmap[ci] = comp;
      comp->touch();
      return *comp;
    }
    else
    {
      it->second->touch();
      return *(it->second);
    }
  }
  else
  {
    it->second->touch();
    return *(it->second);
  }
}

Component* Comploader::createComp(const Compident& ci,
  const Urlmapper& rootmapper)
{
  log_debug("createComp \"" << ci << '"');

  ComponentLibrary& lib = fetchLib(ci.libname);
  Component* comp = lib.create(ci.compname, *this, rootmapper);
  comp->touch();
  return comp;
}

ComponentLibrary& Comploader::fetchLib(const std::string& libname)
{
  log_debug("fetchLib \"" << libname << '"');

  // When first library is fetched static initializers are run,
  // so we disable registation of static factories here.
  staticFactoryAddEnabled = false;

  cxxtools::RdLock lock(libraryMonitor);
  librarymap_type::iterator it = librarymap.find(libname);
  if (it == librarymap.end())
  {
    lock.unlock();

    cxxtools::WrLock wrlock(libraryMonitor);

    // doublecheck after writelock
    it = librarymap.find(libname);
    if (it == librarymap.end())
    {
      // load library
      log_info("load library \"" << libname << '"');
      ComponentLibrary lib;

      bool found = false;
      for (search_path_type::const_iterator p = search_path.begin();
           p != search_path.end(); ++p)
      {
        try
        {
          log_debug("load library \"" << libname << "\" from " << *p << " dir");
          lib = ComponentLibrary(*p, libname);
          found = true;
          break;
        }
        catch (const cxxtools::dl::DlopenError&)
        {
        }
      }

      if (!found)
      {
        try
        {
          log_debug("load library \"" << libname << "\" from current dir");
          lib = ComponentLibrary(".", libname);
        }
        catch (const cxxtools::dl::DlopenError& e)
        {
          log_debug("library \"" << e.getLibname() << "\" in current dir not found - search lib-path");
          lib = ComponentLibrary(libname);
        }
      }

      it = librarymap.insert(librarymap_type::value_type(libname, lib)).first;
    }
  }

  return it->second;
}

void Comploader::cleanup(unsigned seconds)
{
  time_t t = time(0) - seconds;

  cxxtools::RdLock rdlock(componentMonitor);
  for (componentmap_type::iterator it = componentmap.begin();
       it != componentmap.end(); ++it)
  {
    if (it->second->getLastAccesstime() < t)
    {
      // we have something to clean
      rdlock.unlock();

      cxxtools::WrLock wrlock(componentMonitor);
      it = componentmap.begin();
      while (it != componentmap.end())
      {
        if (it->second->getLastAccesstime() < t)
        {
          componentmap_type::iterator it2 = it;
          ++it;
          log_debug("drop " << it2->first);
          it2->second->drop();
          componentmap.erase(it2);
        }
      else
        ++it;
      }
      break;
    }
  }
}

void Comploader::configure(const Tntconfig& config_)
{
  config = &config_;

  Tntconfig::config_entries_type compPath;
  config_.getConfigValues("CompPath", compPath);
  for (Tntconfig::config_entries_type::const_iterator it = compPath.begin();
       it != compPath.end(); ++it)
  {
    if (it->params.size() > 0)
      search_path.push_back(it->params[0]);
  }
}

void Comploader::addStaticFactory(const std::string& component_name,
  ComponentFactory* factory)
{
  if (staticFactoryAddEnabled)
  {
    log_debug("Comploader::addStaticFactory(" << component_name << ", "
      << factory << ')');

    // seach library with empty name

    cxxtools::WrLock wrlock(libraryMonitor);
    librarymap_type::iterator it = librarymap.find(std::string());
    if (it == librarymap.end())
    {
      // empty library not in map - create a new empty library-object
      it = librarymap.insert(
        librarymap_type::value_type(std::string(),
                                    ComponentLibrary())).first;
    }
    it->second.addStaticFactory(component_name, factory);
  }
}

}
<|endoftext|>