<commit_before>#include "Runtime/Graphics/CLight.hpp"

#include <cfloat>

namespace urde {

constexpr zeus::CVector3f kDefaultPosition(0.f, 0.f, 0.f);
constexpr zeus::CVector3f kDefaultDirection(0.f, -1.f, 0.f);

float CLight::CalculateLightRadius() const {
  if (x28_distL < FLT_EPSILON && x2c_distQ < FLT_EPSILON)
    return FLT_MAX;

  float intens = GetIntensity();

  if (x2c_distQ > FLT_EPSILON) {
    if (intens <= FLT_EPSILON)
      return 0.f;
    return std::sqrt(intens / (0.0588235f * x2c_distQ));
  }

  if (x28_distL > FLT_EPSILON)
    return intens / (0.0588235f * x28_distL);

  return 0.f;
}

float CLight::GetIntensity() const {
  if (x4c_24_intensityDirty) {
    x4c_24_intensityDirty = false;
    float coef = 1.f;
    if (x1c_type == ELightType::Custom) {
      coef = x30_angleC;
    }
    x48_cachedIntensity = coef * std::max(x18_color.r(), std::max(x18_color.g(), x18_color.b()));
  }
  return x48_cachedIntensity;
}

float CLight::GetRadius() const {
  if (x4c_25_radiusDirty) {
    x44_cachedRadius = CalculateLightRadius();
    x4c_25_radiusDirty = false;
  }
  return x44_cachedRadius;
}

CLight::CLight(const zeus::CVector3f& pos, const zeus::CVector3f& dir, const zeus::CColor& color, float distC,
               float distL, float distQ, float angleC, float angleL, float angleQ)
: x0_pos(pos)
, xc_dir(dir)
, x18_color(color)
, x24_distC(distC)
, x28_distL(distL)
, x2c_distQ(distQ)
, x30_angleC(angleC)
, x34_angleL(angleL)
, x38_angleQ(angleQ)
, x4c_24_intensityDirty(true)
, x4c_25_radiusDirty(true) {}

CLight::CLight(ELightType type, const zeus::CVector3f& pos, const zeus::CVector3f& dir, const zeus::CColor& color,
               float cutoff)
: x0_pos(pos)
, xc_dir(dir)
, x18_color(color)
, x1c_type(type)
, x20_spotCutoff(cutoff)
, x4c_24_intensityDirty(true)
, x4c_25_radiusDirty(true) {
  switch (type) {
  case ELightType::Spot: {
    const float cosCutoff = std::cos(zeus::degToRad(cutoff));
    x30_angleC = 0.f;
    x34_angleL = -cosCutoff / (1.0f - cosCutoff);
    x38_angleQ = 1.f / (1.0f - cosCutoff);
    break;
  }
  case ELightType::Directional: {
    x24_distC = 1.f;
    x28_distL = 0.f;
    x2c_distQ = 0.f;
    break;
  }
  default:
    break;
  }
}

zeus::CColor CLight::GetNormalIndependentLightingAtPoint(const zeus::CVector3f& point) const {
  if (x1c_type == ELightType::LocalAmbient)
    return x18_color;

  float dist = std::max((x0_pos - point).magnitude(), FLT_EPSILON);
  return x18_color * (1.f / (x2c_distQ * dist * dist + x28_distL * dist + x24_distC));
}

CLight CLight::BuildDirectional(const zeus::CVector3f& dir, const zeus::CColor& color) {
  return CLight(ELightType::Directional, kDefaultPosition, dir, color, 180.f);
}

CLight CLight::BuildSpot(const zeus::CVector3f& pos, const zeus::CVector3f& dir, const zeus::CColor& color,
                         float angle) {
  return CLight(ELightType::Spot, pos, dir, color, angle);
}

CLight CLight::BuildPoint(const zeus::CVector3f& pos, const zeus::CColor& color) {
  return CLight(ELightType::Point, pos, kDefaultDirection, color, 180.f);
}

CLight CLight::BuildCustom(const zeus::CVector3f& pos, const zeus::CVector3f& dir, const zeus::CColor& color,
                           float distC, float distL, float distQ, float angleC, float angleL, float angleQ) {
  return CLight(pos, dir, color, distC, distL, distQ, angleC, angleL, angleQ);
}

CLight CLight::BuildLocalAmbient(const zeus::CVector3f& pos, const zeus::CColor& color) {
  return CLight(ELightType::LocalAmbient, pos, kDefaultDirection, color, 180.f);
}

} // namespace urde
<commit_msg>CLight: Collapse std::max calls into one<commit_after>#include "Runtime/Graphics/CLight.hpp"

#include <cfloat>

namespace urde {

constexpr zeus::CVector3f kDefaultPosition(0.f, 0.f, 0.f);
constexpr zeus::CVector3f kDefaultDirection(0.f, -1.f, 0.f);

float CLight::CalculateLightRadius() const {
  if (x28_distL < FLT_EPSILON && x2c_distQ < FLT_EPSILON)
    return FLT_MAX;

  float intens = GetIntensity();

  if (x2c_distQ > FLT_EPSILON) {
    if (intens <= FLT_EPSILON)
      return 0.f;
    return std::sqrt(intens / (0.0588235f * x2c_distQ));
  }

  if (x28_distL > FLT_EPSILON)
    return intens / (0.0588235f * x28_distL);

  return 0.f;
}

float CLight::GetIntensity() const {
  if (x4c_24_intensityDirty) {
    x4c_24_intensityDirty = false;
    float coef = 1.f;
    if (x1c_type == ELightType::Custom) {
      coef = x30_angleC;
    }
    x48_cachedIntensity = coef * std::max({x18_color.r(), x18_color.g(), x18_color.b()});
  }
  return x48_cachedIntensity;
}

float CLight::GetRadius() const {
  if (x4c_25_radiusDirty) {
    x44_cachedRadius = CalculateLightRadius();
    x4c_25_radiusDirty = false;
  }
  return x44_cachedRadius;
}

CLight::CLight(const zeus::CVector3f& pos, const zeus::CVector3f& dir, const zeus::CColor& color, float distC,
               float distL, float distQ, float angleC, float angleL, float angleQ)
: x0_pos(pos)
, xc_dir(dir)
, x18_color(color)
, x24_distC(distC)
, x28_distL(distL)
, x2c_distQ(distQ)
, x30_angleC(angleC)
, x34_angleL(angleL)
, x38_angleQ(angleQ)
, x4c_24_intensityDirty(true)
, x4c_25_radiusDirty(true) {}

CLight::CLight(ELightType type, const zeus::CVector3f& pos, const zeus::CVector3f& dir, const zeus::CColor& color,
               float cutoff)
: x0_pos(pos)
, xc_dir(dir)
, x18_color(color)
, x1c_type(type)
, x20_spotCutoff(cutoff)
, x4c_24_intensityDirty(true)
, x4c_25_radiusDirty(true) {
  switch (type) {
  case ELightType::Spot: {
    const float cosCutoff = std::cos(zeus::degToRad(cutoff));
    x30_angleC = 0.f;
    x34_angleL = -cosCutoff / (1.0f - cosCutoff);
    x38_angleQ = 1.f / (1.0f - cosCutoff);
    break;
  }
  case ELightType::Directional: {
    x24_distC = 1.f;
    x28_distL = 0.f;
    x2c_distQ = 0.f;
    break;
  }
  default:
    break;
  }
}

zeus::CColor CLight::GetNormalIndependentLightingAtPoint(const zeus::CVector3f& point) const {
  if (x1c_type == ELightType::LocalAmbient)
    return x18_color;

  float dist = std::max((x0_pos - point).magnitude(), FLT_EPSILON);
  return x18_color * (1.f / (x2c_distQ * dist * dist + x28_distL * dist + x24_distC));
}

CLight CLight::BuildDirectional(const zeus::CVector3f& dir, const zeus::CColor& color) {
  return CLight(ELightType::Directional, kDefaultPosition, dir, color, 180.f);
}

CLight CLight::BuildSpot(const zeus::CVector3f& pos, const zeus::CVector3f& dir, const zeus::CColor& color,
                         float angle) {
  return CLight(ELightType::Spot, pos, dir, color, angle);
}

CLight CLight::BuildPoint(const zeus::CVector3f& pos, const zeus::CColor& color) {
  return CLight(ELightType::Point, pos, kDefaultDirection, color, 180.f);
}

CLight CLight::BuildCustom(const zeus::CVector3f& pos, const zeus::CVector3f& dir, const zeus::CColor& color,
                           float distC, float distL, float distQ, float angleC, float angleL, float angleQ) {
  return CLight(pos, dir, color, distC, distL, distQ, angleC, angleL, angleQ);
}

CLight CLight::BuildLocalAmbient(const zeus::CVector3f& pos, const zeus::CColor& color) {
  return CLight(ELightType::LocalAmbient, pos, kDefaultDirection, color, 180.f);
}

} // namespace urde
<|endoftext|>


<commit_before>/*
            This file is part of:
                NoahFrame
            https://github.com/ketoo/NoahGameFrame

   Copyright 2009 - 2020 NoahFrame(NoahGameFrame)

   File creator: lvsheng.huang

   NoahFrame is open-source software and you can redistribute it and/or modify
   it under the terms of the License; besides, anyone who use this file/software must include this copyright announcement.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#include "NFInventoryModule.h"
#include "NFComm/NFMessageDefine/NFProtocolDefine.hpp"
#include "NFComm/NFMessageDefine/NFDefine.pb.h"
#include "NFComm/NFMessageDefine/NFMsgShare.pb.h"

bool NFInventoryModule::Init()
{
	m_pKernelModule = pPluginManager->FindModule<NFIKernelModule>();
	m_pElementModule = pPluginManager->FindModule<NFIElementModule>();
	m_pSceneProcessModule = pPluginManager->FindModule<NFISceneProcessModule>();
	m_pPropertyModule = pPluginManager->FindModule<NFIPropertyModule>();
	m_pLogModule = pPluginManager->FindModule<NFILogModule>();

    return true;
}

bool NFInventoryModule::Shut()
{
    return true;
}

bool NFInventoryModule::Execute()
{

    return true;
}

bool NFInventoryModule::AfterInit()
{

    return true;
}

NFGUID NFInventoryModule::CreateEquip(const NFGUID& self, const std::string& strConfigName )
{
	NF_SHARE_PTR<NFIObject> pObject = m_pKernelModule->GetObject( self );
	if ( NULL == pObject )
	{
		return NULL_OBJECT;
	}

	bool bExist = m_pElementModule->ExistElement( strConfigName );
	if ( !bExist )
	{
		m_pLogModule->LogError(self, "has no this element:" + strConfigName);
		return NULL_OBJECT;
	}

	int nItemType = m_pElementModule->GetPropertyInt32(strConfigName, NFrame::Item::ItemType());
	if ( NFMsg::EItemType::EIT_EQUIP != nItemType )
	{
		m_pLogModule->LogError(self, strConfigName + " has no this item type:" + std::to_string(nItemType));
		return NULL_OBJECT;
	}

	NF_SHARE_PTR<NFIRecord> pRecord = pObject->GetRecordManager()->GetElement( NFrame::Player::InventoryEquipment::ThisName() );
	if (!pRecord)
	{
		return NULL_OBJECT;
	}

	NFGUID ident = m_pKernelModule->CreateGUID();

	NF_SHARE_PTR<NFDataList> var = pRecord->GetInitData();

	var->SetObject(NFrame::Player::InventoryEquipment::GUID, ident);
	var->SetString(NFrame::Player::InventoryEquipment::ConfigID, strConfigName.c_str());
	var->SetInt(NFrame::Player::InventoryEquipment::Date, pPluginManager->GetNowTime());

	int nAddRow = pRecord->AddRow(-1, *var);
	if (nAddRow > 0)
	{
		return pRecord->GetObject(nAddRow, NFrame::Player::InventoryEquipment::GUID);
	}

	return NULL_OBJECT;
}

bool NFInventoryModule::CreateItem(const NFGUID& self, const std::string& strConfigName, const int nCount)
{
	if (nCount <= 0)
	{
		return false;
	}

	NF_SHARE_PTR<NFIObject> pObject = m_pKernelModule->GetObject( self );
	if ( NULL == pObject )
	{
		return false;
	}

	bool bExist = m_pElementModule->ExistElement(NFrame::Item::ThisName(), strConfigName );
	if ( !bExist )
	{
		m_pLogModule->LogError(self, "has no this element:" + strConfigName);
		return false;
	}

	int nItemType = m_pElementModule->GetPropertyInt32(strConfigName, NFrame::Item::ItemType());
	if ( NFMsg::EItemType::EIT_EQUIP == nItemType )
	{
		CreateEquip(self, strConfigName);

		return false;
	}

	const int nSceneID = m_pKernelModule->GetPropertyInt(self, NFrame::Player::SceneID());
	NFMsg::ESceneType eSceneType = (NFMsg::ESceneType)m_pElementModule->GetPropertyInt32(std::to_string(nSceneID), NFrame::Scene::Type());

	return CreateItemInNormalBag(self, strConfigName, nCount);
}

bool NFInventoryModule::DeleteEquip(const NFGUID& self, const NFGUID& id )
{
	if (id.IsNull())
	{
		return false;
	}

	NF_SHARE_PTR<NFIObject> pObject = m_pKernelModule->GetObject( self );
	if (nullptr == pObject)
	{
		return false;
	}

	NF_SHARE_PTR<NFIRecord> pRecord = pObject->GetRecordManager()->GetElement( NFrame::Player::InventoryEquipment::ThisName() );
	if (nullptr == pRecord)
	{
		return false;
	}

	NFDataList varFindResult;
	int nFindRowCount = pRecord->FindObject(NFrame::Player::InventoryEquipment::GUID, id, varFindResult);
	if (nFindRowCount > 0)
	{
		//int nTotalCount = 0;
		for (int i = 0; i < varFindResult.GetCount(); ++i)
		{
			int nFindRow = varFindResult.Int32(i);
			pRecord->Remove(nFindRow);
		}
	}

	return true;
}

bool NFInventoryModule::DeleteItem(const NFGUID& self, const std::string& strItemConfigID, const int nCount )
{
	if(nCount <= 0)
	{
		return false;
	}

	NF_SHARE_PTR<NFIObject> pObject = m_pKernelModule->GetObject( self );
	if ( NULL == pObject )
	{
		return false;
	}

	if (!m_pElementModule->ExistElement(NFrame::Item::ThisName(), strItemConfigID))
	{
		m_pLogModule->LogError(self, "has no this element:" + strItemConfigID);
		return false;
	}

	NF_SHARE_PTR<NFIRecord> pRecord = pObject->GetRecordManager()->GetElement( NFrame::Player::Inventory::ThisName() );
	if (!pRecord)
	{
		return false;
	}

	int nFindRow = pRecord->FindString(NFrame::Player::Inventory::ConfigID, strItemConfigID);
	if (nFindRow > 0)
	{
		int nOldCount = pRecord->GetInt32(nFindRow, NFrame::Player::Inventory::ItemCount);
		if (nOldCount > nCount)
		{
			int nNewCount = nOldCount - nCount;
			pRecord->SetInt(nFindRow, NFrame::Player::Inventory::ItemCount, nNewCount);

			m_pLogModule->LogInfo(self, " DeleteItem:" + strItemConfigID + ", from " + std::to_string(nOldCount) + " to " + std::to_string(nNewCount));
			return true;
		}
		else if (nOldCount == nCount)
		{
			pRecord->Remove(nFindRow);
			m_pLogModule->LogInfo(self, " DeleteItem:" + strItemConfigID + ", from " + std::to_string(nOldCount) + " to 0");
			return true;
		}
	}

	return false;
}

bool NFInventoryModule::EnoughItem(const NFGUID& self, const std::string& strItemConfigID, const int nCount )
{
    if(nCount <= 0)
    {
        return false;
    }

    NF_SHARE_PTR<NFIObject> pObject = m_pKernelModule->GetObject( self );
    if ( NULL == pObject )
    {
        return false;
    }

    bool bExist = m_pElementModule->ExistElement(NFrame::Item::ThisName(), strItemConfigID );
    if ( !bExist )
    {
		m_pLogModule->LogError(self, "has no this element:" + strItemConfigID);
        return false;
    }

    NF_SHARE_PTR<NFIRecord> pRecord = pObject->GetRecordManager()->GetElement( NFrame::Player::Inventory::ThisName() );
    if (!pRecord)
    {
        return false;
    }

	int row = pRecord->FindString(NFrame::Player::Inventory::ConfigID, strItemConfigID);
	if (row >= 0)
	{
		int count = pRecord->GetInt32(row, NFrame::Player::Inventory::ItemCount);

		if (count >= nCount)
		{
			return true;
		}
	}

    return false;
}

bool NFInventoryModule::CreateItemInNormalBag(const NFGUID & self, const std::string & strConfigName, const int nCount)
{
	NF_SHARE_PTR<NFIRecord> pRecord = m_pKernelModule->FindRecord(self, NFrame::Player::Inventory::ThisName());
	if (nullptr == pRecord)
	{
		return false;
	}

	int row = pRecord->FindString(NFrame::Player::Inventory::ConfigID, strConfigName);
	if (row < 0)
	{
		NF_SHARE_PTR<NFDataList> xRowData = pRecord->GetInitData();

		xRowData->SetString(NFrame::Player::Inventory::ConfigID, strConfigName);
		xRowData->SetInt(NFrame::Player::Inventory::ItemCount, nCount);

		int row = pRecord->AddRow(-1, *xRowData);
		if (row < 0)
		{
			m_pLogModule->LogError(self, " cant add item to bag " + strConfigName);
			return false;
		}
	}
	else
	{
		int count = pRecord->GetInt32(row, NFrame::Player::Inventory::ItemCount) + nCount;
		pRecord->SetInt(row, NFrame::Player::Inventory::ItemCount, count);
	}

	m_pLogModule->LogInfo(self, "add item to bag:" + strConfigName + ", count:" + std::to_string(nCount));

	return true;
}<commit_msg>fix bug<commit_after>/*
            This file is part of:
                NoahFrame
            https://github.com/ketoo/NoahGameFrame

   Copyright 2009 - 2020 NoahFrame(NoahGameFrame)

   File creator: lvsheng.huang

   NoahFrame is open-source software and you can redistribute it and/or modify
   it under the terms of the License; besides, anyone who use this file/software must include this copyright announcement.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#include "NFInventoryModule.h"
#include "NFComm/NFMessageDefine/NFProtocolDefine.hpp"
#include "NFComm/NFMessageDefine/NFDefine.pb.h"
#include "NFComm/NFMessageDefine/NFMsgShare.pb.h"

bool NFInventoryModule::Init()
{
	m_pKernelModule = pPluginManager->FindModule<NFIKernelModule>();
	m_pElementModule = pPluginManager->FindModule<NFIElementModule>();
	m_pSceneProcessModule = pPluginManager->FindModule<NFISceneProcessModule>();
	m_pPropertyModule = pPluginManager->FindModule<NFIPropertyModule>();
	m_pLogModule = pPluginManager->FindModule<NFILogModule>();

    return true;
}

bool NFInventoryModule::Shut()
{
    return true;
}

bool NFInventoryModule::Execute()
{

    return true;
}

bool NFInventoryModule::AfterInit()
{

    return true;
}

NFGUID NFInventoryModule::CreateEquip(const NFGUID& self, const std::string& strConfigName )
{
	NF_SHARE_PTR<NFIObject> pObject = m_pKernelModule->GetObject( self );
	if ( NULL == pObject )
	{
		return NULL_OBJECT;
	}

	bool bExist = m_pElementModule->ExistElement( strConfigName );
	if ( !bExist )
	{
		m_pLogModule->LogError(self, "has no this element:" + strConfigName);
		return NULL_OBJECT;
	}

	int nItemType = m_pElementModule->GetPropertyInt32(strConfigName, NFrame::Item::ItemType());
	if ( NFMsg::EItemType::EIT_EQUIP != nItemType )
	{
		m_pLogModule->LogError(self, strConfigName + " has no this item type:" + std::to_string(nItemType));
		return NULL_OBJECT;
	}

	NF_SHARE_PTR<NFIRecord> pRecord = pObject->GetRecordManager()->GetElement( NFrame::Player::InventoryEquipment::ThisName() );
	if (!pRecord)
	{
		return NULL_OBJECT;
	}

	NFGUID ident = m_pKernelModule->CreateGUID();

	NF_SHARE_PTR<NFDataList> var = pRecord->GetInitData();

	var->SetObject(NFrame::Player::InventoryEquipment::GUID, ident);
	var->SetString(NFrame::Player::InventoryEquipment::ConfigID, strConfigName.c_str());
	var->SetInt(NFrame::Player::InventoryEquipment::Date, pPluginManager->GetNowTime());

	int nAddRow = pRecord->AddRow(-1, *var);
	if (nAddRow >= 0)
	{
		return pRecord->GetObject(nAddRow, NFrame::Player::InventoryEquipment::GUID);
	}

	return NULL_OBJECT;
}

bool NFInventoryModule::CreateItem(const NFGUID& self, const std::string& strConfigName, const int nCount)
{
	if (nCount <= 0)
	{
		return false;
	}

	NF_SHARE_PTR<NFIObject> pObject = m_pKernelModule->GetObject( self );
	if ( NULL == pObject )
	{
		return false;
	}

	bool bExist = m_pElementModule->ExistElement(NFrame::Item::ThisName(), strConfigName );
	if ( !bExist )
	{
		m_pLogModule->LogError(self, "has no this element:" + strConfigName);
		return false;
	}

	int nItemType = m_pElementModule->GetPropertyInt32(strConfigName, NFrame::Item::ItemType());
	if ( NFMsg::EItemType::EIT_EQUIP == nItemType )
	{
		CreateEquip(self, strConfigName);

		return false;
	}

	const int nSceneID = m_pKernelModule->GetPropertyInt(self, NFrame::Player::SceneID());
	NFMsg::ESceneType eSceneType = (NFMsg::ESceneType)m_pElementModule->GetPropertyInt32(std::to_string(nSceneID), NFrame::Scene::Type());

	return CreateItemInNormalBag(self, strConfigName, nCount);
}

bool NFInventoryModule::DeleteEquip(const NFGUID& self, const NFGUID& id )
{
	if (id.IsNull())
	{
		return false;
	}

	NF_SHARE_PTR<NFIObject> pObject = m_pKernelModule->GetObject( self );
	if (nullptr == pObject)
	{
		return false;
	}

	NF_SHARE_PTR<NFIRecord> pRecord = pObject->GetRecordManager()->GetElement( NFrame::Player::InventoryEquipment::ThisName() );
	if (nullptr == pRecord)
	{
		return false;
	}

	NFDataList varFindResult;
	int nFindRowCount = pRecord->FindObject(NFrame::Player::InventoryEquipment::GUID, id, varFindResult);
	if (nFindRowCount > 0)
	{
		//int nTotalCount = 0;
		for (int i = 0; i < varFindResult.GetCount(); ++i)
		{
			int nFindRow = varFindResult.Int32(i);
			pRecord->Remove(nFindRow);
		}
	}

	return true;
}

bool NFInventoryModule::DeleteItem(const NFGUID& self, const std::string& strItemConfigID, const int nCount )
{
	if(nCount <= 0)
	{
		return false;
	}

	NF_SHARE_PTR<NFIObject> pObject = m_pKernelModule->GetObject( self );
	if ( NULL == pObject )
	{
		return false;
	}

	if (!m_pElementModule->ExistElement(NFrame::Item::ThisName(), strItemConfigID))
	{
		m_pLogModule->LogError(self, "has no this element:" + strItemConfigID);
		return false;
	}

	NF_SHARE_PTR<NFIRecord> pRecord = pObject->GetRecordManager()->GetElement( NFrame::Player::Inventory::ThisName() );
	if (!pRecord)
	{
		return false;
	}

	int nFindRow = pRecord->FindString(NFrame::Player::Inventory::ConfigID, strItemConfigID);
	if (nFindRow >= 0)
	{
		int nOldCount = pRecord->GetInt32(nFindRow, NFrame::Player::Inventory::ItemCount);
		if (nOldCount > nCount)
		{
			int nNewCount = nOldCount - nCount;
			pRecord->SetInt(nFindRow, NFrame::Player::Inventory::ItemCount, nNewCount);

			m_pLogModule->LogInfo(self, " DeleteItem:" + strItemConfigID + ", from " + std::to_string(nOldCount) + " to " + std::to_string(nNewCount));
			return true;
		}
		else if (nOldCount == nCount)
		{
			pRecord->Remove(nFindRow);
			m_pLogModule->LogInfo(self, " DeleteItem:" + strItemConfigID + ", from " + std::to_string(nOldCount) + " to 0");
			return true;
		}
	}

	return false;
}

bool NFInventoryModule::EnoughItem(const NFGUID& self, const std::string& strItemConfigID, const int nCount )
{
    if(nCount <= 0)
    {
        return false;
    }

    NF_SHARE_PTR<NFIObject> pObject = m_pKernelModule->GetObject( self );
    if ( NULL == pObject )
    {
        return false;
    }

    bool bExist = m_pElementModule->ExistElement(NFrame::Item::ThisName(), strItemConfigID );
    if ( !bExist )
    {
		m_pLogModule->LogError(self, "has no this element:" + strItemConfigID);
        return false;
    }

    NF_SHARE_PTR<NFIRecord> pRecord = pObject->GetRecordManager()->GetElement( NFrame::Player::Inventory::ThisName() );
    if (!pRecord)
    {
        return false;
    }

	int row = pRecord->FindString(NFrame::Player::Inventory::ConfigID, strItemConfigID);
	if (row >= 0)
	{
		int count = pRecord->GetInt32(row, NFrame::Player::Inventory::ItemCount);

		if (count >= nCount)
		{
			return true;
		}
	}

    return false;
}

bool NFInventoryModule::CreateItemInNormalBag(const NFGUID & self, const std::string & strConfigName, const int nCount)
{
	NF_SHARE_PTR<NFIRecord> pRecord = m_pKernelModule->FindRecord(self, NFrame::Player::Inventory::ThisName());
	if (nullptr == pRecord)
	{
		return false;
	}

	int row = pRecord->FindString(NFrame::Player::Inventory::ConfigID, strConfigName);
	if (row < 0)
	{
		NF_SHARE_PTR<NFDataList> xRowData = pRecord->GetInitData();

		xRowData->SetString(NFrame::Player::Inventory::ConfigID, strConfigName);
		xRowData->SetInt(NFrame::Player::Inventory::ItemCount, nCount);

		int row = pRecord->AddRow(-1, *xRowData);
		if (row < 0)
		{
			m_pLogModule->LogError(self, " cant add item to bag " + strConfigName);
			return false;
		}
	}
	else
	{
		int count = pRecord->GetInt32(row, NFrame::Player::Inventory::ItemCount) + nCount;
		pRecord->SetInt(row, NFrame::Player::Inventory::ItemCount, count);
	}

	m_pLogModule->LogInfo(self, "add item to bag:" + strConfigName + ", count:" + std::to_string(nCount));

	return true;
}<|endoftext|>


<commit_before>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "ConstantPropagationWholeProgramState.h"

#include "IPConstantPropagationAnalysis.h"
#include "Trace.h"
#include "Walkers.h"

using namespace constant_propagation;

namespace {

/*
 * Walk all the static or instance fields in :cls, copying their bindings in
 * :field_env over to :field_partition.
 */
void set_fields_in_partition(const DexClass* cls,
                             const FieldEnvironment& field_env,
                             const FieldType& field_type,
                             ConstantFieldPartition* field_partition) {
  // Note that we *must* iterate over the list of fields in the class and not
  // the bindings in field_env here. This ensures that fields whose values are
  // unknown (and therefore implicitly represented by Top in the field_env)
  // get correctly bound to Top in field_partition (which defaults its
  // bindings to Bottom).
  const auto& fields =
      field_type == FieldType::STATIC ? cls->get_sfields() : cls->get_ifields();
  for (auto& field : fields) {
    auto value = field_env.get(field);
    if (!value.is_top()) {
      TRACE(ICONSTP, 2, "%s has value %s after <clinit> or <init>", SHOW(field),
            SHOW(value));
      always_assert(field->get_class() == cls->get_type());
    } else {
      TRACE(ICONSTP, 2, "%s has unknown value after <clinit> or <init>",
            SHOW(field));
    }
    field_partition->set(field, value);
  }
}

/*
 * Record in :field_partition the values of the static fields after the class
 * initializers have finished executing.
 *
 * XXX this assumes that there are no cycles in the class initialization graph!
 */
void analyze_clinits(const Scope& scope,
                     const interprocedural::FixpointIterator& fp_iter,
                     ConstantFieldPartition* field_partition) {
  for (DexClass* cls : scope) {
    auto clinit = cls->get_clinit();
    if (clinit == nullptr) {
      // If there is no class initializer, then the initial field values are
      // simply the DexEncodedValues.
      ConstantEnvironment env;
      set_encoded_values(cls, &env);
      set_fields_in_partition(cls, env.get_field_environment(),
                              FieldType::STATIC, field_partition);
      continue;
    }
    IRCode* code = clinit->get_code();
    auto& cfg = code->cfg();
    auto intra_cp = fp_iter.get_intraprocedural_analysis(clinit);
    auto env = intra_cp->get_exit_state_at(cfg.exit_block());
    set_fields_in_partition(cls, env.get_field_environment(), FieldType::STATIC,
                            field_partition);
  }
}

bool analyze_gets_helper(const WholeProgramState* whole_program_state,
                         const IRInstruction* insn,
                         ConstantEnvironment* env) {
  if (whole_program_state == nullptr) {
    return false;
  }
  auto field = resolve_field(insn->get_field());
  if (field == nullptr) {
    return false;
  }
  auto value = whole_program_state->get_field_value(field);
  if (value.is_top()) {
    return false;
  }
  env->set(RESULT_REGISTER, value);
  return true;
}

bool not_eligible_ifield(DexField* field) {
  return is_static(field) || field->is_external() || !can_delete(field) ||
         is_volatile(field);
}

/**
 * Initialize non-external, can be deleted instance fields' value to be 0.
 */
void initialize_ifields(
    const Scope& scope,
    ConstantFieldPartition* field_partition,
    const std::unordered_set<const DexField*>& definitely_assigned_ifields) {
  walk::fields(scope, [&](DexField* field) {
    if (not_eligible_ifield(field)) {
      return;
    }
    // For instance fields that are always written to before they are read, the
    // initial 0 value is not observable, so we don't even have to include it.
    auto value = definitely_assigned_ifields.count(field)
                     ? SignedConstantDomain::bottom()
                     : SignedConstantDomain(0);
    field_partition->set(field, value);
  });
}

} // namespace

namespace constant_propagation {

WholeProgramState::WholeProgramState(
    const Scope& scope,
    const interprocedural::FixpointIterator& fp_iter,
    const std::unordered_set<DexMethod*>& non_true_virtuals,
    const std::unordered_set<const DexType*>& field_blocklist,
    const std::unordered_set<const DexField*>& definitely_assigned_ifields)
    : m_field_blocklist(field_blocklist) {

  walk::fields(scope, [&](DexField* field) {
    // We exclude those marked by keep rules: keep-marked fields may be
    // written to by non-Dex bytecode.
    // All fields not in m_known_fields will be bound to Top.
    if (field_blocklist.count(field->get_class())) {
      return;
    }
    if (is_static(field) && !root(field)) {
      m_known_fields.emplace(field);
    }
    if (not_eligible_ifield(field)) {
      return;
    }
    m_known_fields.emplace(field);
  });
  // Put non-root non true virtual methods in known methods.
  for (const auto& non_true_virtual : non_true_virtuals) {
    if (!root(non_true_virtual) && non_true_virtual->get_code()) {
      m_known_methods.emplace(non_true_virtual);
    }
  }
  walk::code(scope, [&](DexMethod* method, const IRCode&) {
    if (!method->is_virtual() && method->get_code()) {
      // Put non virtual methods in known methods.
      m_known_methods.emplace(method);
    }
  });
  analyze_clinits(scope, fp_iter, &m_field_partition);
  collect(scope, fp_iter, definitely_assigned_ifields);
}

WholeProgramState::WholeProgramState(
    const Scope& scope,
    const interprocedural::FixpointIterator& fp_iter,
    const std::unordered_set<DexMethod*>& non_true_virtuals,
    const std::unordered_set<const DexType*>& field_blocklist,
    const std::unordered_set<const DexField*>& definitely_assigned_ifields,
    const call_graph::Graph& call_graph)
    : WholeProgramState(scope,
                        fp_iter,
                        non_true_virtuals,
                        field_blocklist,
                        definitely_assigned_ifields) {
  m_call_graph = call_graph;
}
/*
 * Walk over the entire program, doing a join over the values written to each
 * field, as well as a join over the values returned by each method.
 */
void WholeProgramState::collect(
    const Scope& scope,
    const interprocedural::FixpointIterator& fp_iter,
    const std::unordered_set<const DexField*>& definitely_assigned_ifields) {
  initialize_ifields(scope, &m_field_partition, definitely_assigned_ifields);
  ConcurrentMap<const DexField*, std::vector<ConstantValue>> fields_value_tmp;
  ConcurrentMap<const DexMethod*, std::vector<ConstantValue>> methods_value_tmp;
  walk::parallel::methods(scope, [&](DexMethod* method) {
    IRCode* code = method->get_code();
    if (code == nullptr) {
      return;
    }
    auto& cfg = code->cfg();
    auto intra_cp = fp_iter.get_intraprocedural_analysis(method);
    for (cfg::Block* b : cfg.blocks()) {
      auto env = intra_cp->get_entry_state_at(b);
      auto last_insn = b->get_last_insn();
      for (auto& mie : InstructionIterable(b)) {
        auto* insn = mie.insn;
        intra_cp->analyze_instruction(insn, &env, insn == last_insn->insn);
        collect_field_values(insn, env,
                             method::is_clinit(method) ? method->get_class()
                                                       : nullptr,
                             &fields_value_tmp);
        collect_return_values(insn, env, method, &methods_value_tmp);
      }
    }
  });
  for (const auto& pair : fields_value_tmp) {
    for (auto& value : pair.second) {
      m_field_partition.update(pair.first, [&value](auto* current_value) {
        current_value->join_with(value);
      });
    }
  }
  for (const auto& pair : methods_value_tmp) {
    for (auto& value : pair.second) {
      m_method_partition.update(pair.first, [&value](auto* current_value) {
        current_value->join_with(value);
      });
    }
  }
}

/*
 * For each field, do a join over all the values that may have been
 * written to it at any point in the program.
 *
 * If we are encountering a static field write of some value to Foo.someField
 * in the body of Foo.<clinit>, don't do anything -- that value will only be
 * visible to other methods if it remains unchanged up until the end of the
 * <clinit>. In that case, analyze_clinits() will record it.
 */
void WholeProgramState::collect_field_values(
    const IRInstruction* insn,
    const ConstantEnvironment& env,
    const DexType* clinit_cls,
    ConcurrentMap<const DexField*, std::vector<ConstantValue>>*
        fields_value_tmp) {
  if (!opcode::is_an_sput(insn->opcode()) &&
      !opcode::is_an_iput(insn->opcode())) {
    return;
  }
  auto field = resolve_field(insn->get_field());
  if (field != nullptr && m_known_fields.count(field)) {
    if (opcode::is_an_sput(insn->opcode()) &&
        field->get_class() == clinit_cls) {
      return;
    }
    auto value = env.get(insn->src(0));
    fields_value_tmp->update(
        field,
        [value](const DexField*,
                std::vector<ConstantValue>& s,
                bool /* exists */) { s.emplace_back(value); });
  }
}

/*
 * For each method, do a join over all the values that can be returned by it.
 *
 * If there are no reachable return opcodes in the method, then it never
 * returns. Its return value will be represented by Bottom in our analysis.
 */
void WholeProgramState::collect_return_values(
    const IRInstruction* insn,
    const ConstantEnvironment& env,
    const DexMethod* method,
    ConcurrentMap<const DexMethod*, std::vector<ConstantValue>>*
        methods_value_tmp) {
  auto op = insn->opcode();
  if (!opcode::is_a_return(op)) {
    return;
  }
  if (op == OPCODE_RETURN_VOID) {
    // We must set the binding to Top here to record the fact that this method
    // does indeed return -- even though `void` is not actually a return value,
    // this tells us that the code following any invoke of this method is
    // reachable.
    methods_value_tmp->update(
        method,
        [](const DexMethod*, std::vector<ConstantValue>& s, bool /* exists */) {
          s.emplace_back(ConstantValue::top());
        });
    return;
  }
  auto value = env.get(insn->src(0));
  methods_value_tmp->update(
      method,
      [value](const DexMethod*,
              std::vector<ConstantValue>& s,
              bool /* exists */) { s.emplace_back(value); });
}

void WholeProgramState::collect_static_finals(const DexClass* cls,
                                              FieldEnvironment field_env) {
  for (auto* field : cls->get_sfields()) {
    if (is_static(field) && is_final(field) && !field->is_external() &&
        m_field_blocklist.count(field->get_class()) == 0) {
      m_known_fields.emplace(field);
    } else {
      field_env.set(field, ConstantValue::top());
    }
  }
  set_fields_in_partition(cls, field_env, FieldType::STATIC,
                          &m_field_partition);
}

void WholeProgramState::collect_instance_finals(
    const DexClass* cls,
    const EligibleIfields& eligible_ifields,
    FieldEnvironment field_env) {
  always_assert(!cls->is_external());
  if (cls->get_ctors().size() > 1) {
    // Not dealing with instance field in class not having exact 1 constructor
    // now. TODO(suree404): Might be able to improve?
    for (auto* field : cls->get_ifields()) {
      field_env.set(field, ConstantValue::top());
    }
  } else {
    for (auto* field : cls->get_ifields()) {
      if (eligible_ifields.count(field) &&
          m_field_blocklist.count(field->get_class()) == 0) {
        m_known_fields.emplace(field);
      } else {
        field_env.set(field, ConstantValue::top());
      }
    }
  }
  set_fields_in_partition(cls, field_env, FieldType::INSTANCE,
                          &m_field_partition);
}

bool WholeProgramAwareAnalyzer::analyze_sget(
    const WholeProgramState* whole_program_state,
    const IRInstruction* insn,
    ConstantEnvironment* env) {
  return analyze_gets_helper(whole_program_state, insn, env);
}

bool WholeProgramAwareAnalyzer::analyze_iget(
    const WholeProgramState* whole_program_state,
    const IRInstruction* insn,
    ConstantEnvironment* env) {
  return analyze_gets_helper(whole_program_state, insn, env);
}

bool WholeProgramAwareAnalyzer::analyze_invoke(
    const WholeProgramState* whole_program_state,
    const IRInstruction* insn,
    ConstantEnvironment* env) {
  if (whole_program_state == nullptr) {
    return false;
  }
  if (whole_program_state->has_call_graph()) {
    auto method = resolve_method(insn->get_method(), opcode_to_search(insn));
    if (method == nullptr && opcode_to_search(insn) == MethodSearch::Virtual) {
      method =
          resolve_method(insn->get_method(), MethodSearch::InterfaceVirtual);
    }
    if (method == nullptr) {
      return false;
    }
    if (whole_program_state->method_is_dynamic(method)) {
      return false;
    }
    auto value = whole_program_state->get_return_value_from_cg(insn);
    if (value.is_top()) {
      return false;
    }
    env->set(RESULT_REGISTER, value);
    return true;
  }
  auto op = insn->opcode();
  if (op != OPCODE_INVOKE_DIRECT && op != OPCODE_INVOKE_STATIC &&
      op != OPCODE_INVOKE_VIRTUAL) {
    return false;
  }
  auto method = resolve_method(insn->get_method(), opcode_to_search(insn));
  if (method == nullptr) {
    return false;
  }
  auto value = whole_program_state->get_return_value(method);
  if (value.is_top()) {
    return false;
  }
  env->set(RESULT_REGISTER, value);
  return true;
}

} // namespace constant_propagation
<commit_msg>Exclude root static fields<commit_after>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "ConstantPropagationWholeProgramState.h"

#include "IPConstantPropagationAnalysis.h"
#include "Trace.h"
#include "Walkers.h"

using namespace constant_propagation;

namespace {

/*
 * Walk all the static or instance fields in :cls, copying their bindings in
 * :field_env over to :field_partition.
 */
void set_fields_in_partition(const DexClass* cls,
                             const FieldEnvironment& field_env,
                             const FieldType& field_type,
                             ConstantFieldPartition* field_partition) {
  // Note that we *must* iterate over the list of fields in the class and not
  // the bindings in field_env here. This ensures that fields whose values are
  // unknown (and therefore implicitly represented by Top in the field_env)
  // get correctly bound to Top in field_partition (which defaults its
  // bindings to Bottom).
  const auto& fields =
      field_type == FieldType::STATIC ? cls->get_sfields() : cls->get_ifields();
  for (auto& field : fields) {
    auto value = field_env.get(field);
    if (!value.is_top()) {
      TRACE(ICONSTP, 2, "%s has value %s after <clinit> or <init>", SHOW(field),
            SHOW(value));
      always_assert(field->get_class() == cls->get_type());
    } else {
      TRACE(ICONSTP, 2, "%s has unknown value after <clinit> or <init>",
            SHOW(field));
    }
    field_partition->set(field, value);
  }
}

/*
 * Record in :field_partition the values of the static fields after the class
 * initializers have finished executing.
 *
 * XXX this assumes that there are no cycles in the class initialization graph!
 */
void analyze_clinits(const Scope& scope,
                     const interprocedural::FixpointIterator& fp_iter,
                     ConstantFieldPartition* field_partition) {
  for (DexClass* cls : scope) {
    auto clinit = cls->get_clinit();
    if (clinit == nullptr) {
      // If there is no class initializer, then the initial field values are
      // simply the DexEncodedValues.
      ConstantEnvironment env;
      set_encoded_values(cls, &env);
      set_fields_in_partition(cls, env.get_field_environment(),
                              FieldType::STATIC, field_partition);
      continue;
    }
    IRCode* code = clinit->get_code();
    auto& cfg = code->cfg();
    auto intra_cp = fp_iter.get_intraprocedural_analysis(clinit);
    auto env = intra_cp->get_exit_state_at(cfg.exit_block());
    set_fields_in_partition(cls, env.get_field_environment(), FieldType::STATIC,
                            field_partition);
  }
}

bool analyze_gets_helper(const WholeProgramState* whole_program_state,
                         const IRInstruction* insn,
                         ConstantEnvironment* env) {
  if (whole_program_state == nullptr) {
    return false;
  }
  auto field = resolve_field(insn->get_field());
  if (field == nullptr) {
    return false;
  }
  auto value = whole_program_state->get_field_value(field);
  if (value.is_top()) {
    return false;
  }
  env->set(RESULT_REGISTER, value);
  return true;
}

bool not_eligible_ifield(DexField* field) {
  return is_static(field) || field->is_external() || !can_delete(field) ||
         is_volatile(field);
}

/**
 * Initialize non-external, can be deleted instance fields' value to be 0.
 */
void initialize_ifields(
    const Scope& scope,
    ConstantFieldPartition* field_partition,
    const std::unordered_set<const DexField*>& definitely_assigned_ifields) {
  walk::fields(scope, [&](DexField* field) {
    if (not_eligible_ifield(field)) {
      return;
    }
    // For instance fields that are always written to before they are read, the
    // initial 0 value is not observable, so we don't even have to include it.
    auto value = definitely_assigned_ifields.count(field)
                     ? SignedConstantDomain::bottom()
                     : SignedConstantDomain(0);
    field_partition->set(field, value);
  });
}

} // namespace

namespace constant_propagation {

WholeProgramState::WholeProgramState(
    const Scope& scope,
    const interprocedural::FixpointIterator& fp_iter,
    const std::unordered_set<DexMethod*>& non_true_virtuals,
    const std::unordered_set<const DexType*>& field_blocklist,
    const std::unordered_set<const DexField*>& definitely_assigned_ifields)
    : m_field_blocklist(field_blocklist) {

  walk::fields(scope, [&](DexField* field) {
    // We exclude those marked by keep rules: keep-marked fields may be
    // written to by non-Dex bytecode.
    // All fields not in m_known_fields will be bound to Top.
    if (field_blocklist.count(field->get_class())) {
      return;
    }
    if (is_static(field) && !root(field)) {
      m_known_fields.emplace(field);
    }
    if (not_eligible_ifield(field)) {
      return;
    }
    m_known_fields.emplace(field);
  });
  // Put non-root non true virtual methods in known methods.
  for (const auto& non_true_virtual : non_true_virtuals) {
    if (!root(non_true_virtual) && non_true_virtual->get_code()) {
      m_known_methods.emplace(non_true_virtual);
    }
  }
  walk::code(scope, [&](DexMethod* method, const IRCode&) {
    if (!method->is_virtual() && method->get_code()) {
      // Put non virtual methods in known methods.
      m_known_methods.emplace(method);
    }
  });
  analyze_clinits(scope, fp_iter, &m_field_partition);
  collect(scope, fp_iter, definitely_assigned_ifields);
}

WholeProgramState::WholeProgramState(
    const Scope& scope,
    const interprocedural::FixpointIterator& fp_iter,
    const std::unordered_set<DexMethod*>& non_true_virtuals,
    const std::unordered_set<const DexType*>& field_blocklist,
    const std::unordered_set<const DexField*>& definitely_assigned_ifields,
    const call_graph::Graph& call_graph)
    : WholeProgramState(scope,
                        fp_iter,
                        non_true_virtuals,
                        field_blocklist,
                        definitely_assigned_ifields) {
  m_call_graph = call_graph;
}
/*
 * Walk over the entire program, doing a join over the values written to each
 * field, as well as a join over the values returned by each method.
 */
void WholeProgramState::collect(
    const Scope& scope,
    const interprocedural::FixpointIterator& fp_iter,
    const std::unordered_set<const DexField*>& definitely_assigned_ifields) {
  initialize_ifields(scope, &m_field_partition, definitely_assigned_ifields);
  ConcurrentMap<const DexField*, std::vector<ConstantValue>> fields_value_tmp;
  ConcurrentMap<const DexMethod*, std::vector<ConstantValue>> methods_value_tmp;
  walk::parallel::methods(scope, [&](DexMethod* method) {
    IRCode* code = method->get_code();
    if (code == nullptr) {
      return;
    }
    auto& cfg = code->cfg();
    auto intra_cp = fp_iter.get_intraprocedural_analysis(method);
    for (cfg::Block* b : cfg.blocks()) {
      auto env = intra_cp->get_entry_state_at(b);
      auto last_insn = b->get_last_insn();
      for (auto& mie : InstructionIterable(b)) {
        auto* insn = mie.insn;
        intra_cp->analyze_instruction(insn, &env, insn == last_insn->insn);
        collect_field_values(insn, env,
                             method::is_clinit(method) ? method->get_class()
                                                       : nullptr,
                             &fields_value_tmp);
        collect_return_values(insn, env, method, &methods_value_tmp);
      }
    }
  });
  for (const auto& pair : fields_value_tmp) {
    for (auto& value : pair.second) {
      m_field_partition.update(pair.first, [&value](auto* current_value) {
        current_value->join_with(value);
      });
    }
  }
  for (const auto& pair : methods_value_tmp) {
    for (auto& value : pair.second) {
      m_method_partition.update(pair.first, [&value](auto* current_value) {
        current_value->join_with(value);
      });
    }
  }
}

/*
 * For each field, do a join over all the values that may have been
 * written to it at any point in the program.
 *
 * If we are encountering a static field write of some value to Foo.someField
 * in the body of Foo.<clinit>, don't do anything -- that value will only be
 * visible to other methods if it remains unchanged up until the end of the
 * <clinit>. In that case, analyze_clinits() will record it.
 */
void WholeProgramState::collect_field_values(
    const IRInstruction* insn,
    const ConstantEnvironment& env,
    const DexType* clinit_cls,
    ConcurrentMap<const DexField*, std::vector<ConstantValue>>*
        fields_value_tmp) {
  if (!opcode::is_an_sput(insn->opcode()) &&
      !opcode::is_an_iput(insn->opcode())) {
    return;
  }
  auto field = resolve_field(insn->get_field());
  if (field != nullptr && m_known_fields.count(field)) {
    if (opcode::is_an_sput(insn->opcode()) &&
        field->get_class() == clinit_cls) {
      return;
    }
    auto value = env.get(insn->src(0));
    fields_value_tmp->update(
        field,
        [value](const DexField*,
                std::vector<ConstantValue>& s,
                bool /* exists */) { s.emplace_back(value); });
  }
}

/*
 * For each method, do a join over all the values that can be returned by it.
 *
 * If there are no reachable return opcodes in the method, then it never
 * returns. Its return value will be represented by Bottom in our analysis.
 */
void WholeProgramState::collect_return_values(
    const IRInstruction* insn,
    const ConstantEnvironment& env,
    const DexMethod* method,
    ConcurrentMap<const DexMethod*, std::vector<ConstantValue>>*
        methods_value_tmp) {
  auto op = insn->opcode();
  if (!opcode::is_a_return(op)) {
    return;
  }
  if (op == OPCODE_RETURN_VOID) {
    // We must set the binding to Top here to record the fact that this method
    // does indeed return -- even though `void` is not actually a return value,
    // this tells us that the code following any invoke of this method is
    // reachable.
    methods_value_tmp->update(
        method,
        [](const DexMethod*, std::vector<ConstantValue>& s, bool /* exists */) {
          s.emplace_back(ConstantValue::top());
        });
    return;
  }
  auto value = env.get(insn->src(0));
  methods_value_tmp->update(
      method,
      [value](const DexMethod*,
              std::vector<ConstantValue>& s,
              bool /* exists */) { s.emplace_back(value); });
}

void WholeProgramState::collect_static_finals(const DexClass* cls,
                                              FieldEnvironment field_env) {
  for (auto* field : cls->get_sfields()) {
    if (is_static(field) && !root(field) && is_final(field) &&
        !field->is_external() &&
        m_field_blocklist.count(field->get_class()) == 0) {
      m_known_fields.emplace(field);
    } else {
      field_env.set(field, ConstantValue::top());
    }
  }
  set_fields_in_partition(cls, field_env, FieldType::STATIC,
                          &m_field_partition);
}

void WholeProgramState::collect_instance_finals(
    const DexClass* cls,
    const EligibleIfields& eligible_ifields,
    FieldEnvironment field_env) {
  always_assert(!cls->is_external());
  if (cls->get_ctors().size() > 1) {
    // Not dealing with instance field in class not having exact 1 constructor
    // now. TODO(suree404): Might be able to improve?
    for (auto* field : cls->get_ifields()) {
      field_env.set(field, ConstantValue::top());
    }
  } else {
    for (auto* field : cls->get_ifields()) {
      if (eligible_ifields.count(field) &&
          m_field_blocklist.count(field->get_class()) == 0) {
        m_known_fields.emplace(field);
      } else {
        field_env.set(field, ConstantValue::top());
      }
    }
  }
  set_fields_in_partition(cls, field_env, FieldType::INSTANCE,
                          &m_field_partition);
}

bool WholeProgramAwareAnalyzer::analyze_sget(
    const WholeProgramState* whole_program_state,
    const IRInstruction* insn,
    ConstantEnvironment* env) {
  return analyze_gets_helper(whole_program_state, insn, env);
}

bool WholeProgramAwareAnalyzer::analyze_iget(
    const WholeProgramState* whole_program_state,
    const IRInstruction* insn,
    ConstantEnvironment* env) {
  return analyze_gets_helper(whole_program_state, insn, env);
}

bool WholeProgramAwareAnalyzer::analyze_invoke(
    const WholeProgramState* whole_program_state,
    const IRInstruction* insn,
    ConstantEnvironment* env) {
  if (whole_program_state == nullptr) {
    return false;
  }
  if (whole_program_state->has_call_graph()) {
    auto method = resolve_method(insn->get_method(), opcode_to_search(insn));
    if (method == nullptr && opcode_to_search(insn) == MethodSearch::Virtual) {
      method =
          resolve_method(insn->get_method(), MethodSearch::InterfaceVirtual);
    }
    if (method == nullptr) {
      return false;
    }
    if (whole_program_state->method_is_dynamic(method)) {
      return false;
    }
    auto value = whole_program_state->get_return_value_from_cg(insn);
    if (value.is_top()) {
      return false;
    }
    env->set(RESULT_REGISTER, value);
    return true;
  }
  auto op = insn->opcode();
  if (op != OPCODE_INVOKE_DIRECT && op != OPCODE_INVOKE_STATIC &&
      op != OPCODE_INVOKE_VIRTUAL) {
    return false;
  }
  auto method = resolve_method(insn->get_method(), opcode_to_search(insn));
  if (method == nullptr) {
    return false;
  }
  auto value = whole_program_state->get_return_value(method);
  if (value.is_top()) {
    return false;
  }
  env->set(RESULT_REGISTER, value);
  return true;
}

} // namespace constant_propagation
<|endoftext|>


<commit_before>#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "plotwidget.h"
#include "signalhandler.h"
#include "signaldata.h"
#include "selectsignaldialog.h"
#include "signaldescription.h"
#include "lcmthread.h"

#include <QLabel>
#include <QLayout>
#include <QApplication>
#include <QDebug>
#include <QScrollArea>
#include <QPushButton>
#include <QShortcut>
#include <QFileDialog>
#include <QInputDialog>
#include <QTimer>

#include "qjson.h"

#include <cstdio>
#include <limits>

class MainWindow::Internal : public Ui::MainWindow
{
public:

};

MainWindow::MainWindow(QWidget* parent): QMainWindow(parent)
{
  mInternal = new Internal;
  mInternal->setupUi(this);

  mPlaying = false;
  this->setWindowTitle("Signal Scope");

  mLCMThread = new LCMThread;
  mLCMThread->start();

  mScrollArea = new QScrollArea;
  mPlotArea = new QWidget;
  mPlotLayout = new QVBoxLayout(mPlotArea);

  mScrollArea->setWidget(mPlotArea);
  mScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  mScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
  mScrollArea->setWidgetResizable(true);
  this->setCentralWidget(mScrollArea);

  mInternal->ActionQuit->setIcon(qApp->style()->standardIcon(QStyle::SP_TrashIcon));
  mInternal->ActionOpen->setIcon(qApp->style()->standardIcon(QStyle::SP_DialogOpenButton));
  mInternal->ActionSave->setIcon(qApp->style()->standardIcon(QStyle::SP_DialogSaveButton));
  mInternal->ActionPause->setIcon(qApp->style()->standardIcon(QStyle::SP_MediaPlay));
  mInternal->ActionClearHistory->setIcon(qApp->style()->standardIcon(QStyle::SP_TrashIcon));
  mInternal->ActionAddPlot->setIcon(qApp->style()->standardIcon(QStyle::SP_TrashIcon));
  //QStyle::SP_DialogDiscardButton

  this->connect(mInternal->ActionQuit, SIGNAL(activated()), SLOT(close()));
  this->connect(mInternal->ActionOpen, SIGNAL(activated()), SLOT(onOpenSettings()));
  this->connect(mInternal->ActionSave, SIGNAL(activated()), SLOT(onSaveSettings()));
  this->connect(mInternal->ActionPause, SIGNAL(activated()), SLOT(onTogglePause()));
  this->connect(mInternal->ActionAddPlot, SIGNAL(activated()), SLOT(onNewPlotClicked()));
  this->connect(mInternal->ActionClearHistory, SIGNAL(activated()), SLOT(onClearHistory()));

  this->connect(mInternal->ActionBackgroundColor, SIGNAL(activated()), SLOT(onChooseBackgroundColor()));
  this->connect(mInternal->ActionPointSize, SIGNAL(activated()), SLOT(onChoosePointSize()));

  mRedrawTimer = new QTimer(this);
  //mRedrawTimer->setSingleShot(true);
  this->connect(mRedrawTimer, SIGNAL(timeout()), this, SLOT(onRedrawPlots()));

  this->resize(1024,800);
  this->handleCommandLineArgs();

  this->onTogglePause();
}

MainWindow::~MainWindow()
{

  QString settingsFile = QDir::homePath() + "/.signal_scope.json";
  this->saveSettings(settingsFile);

  mLCMThread->stop();
  mLCMThread->wait(250);
  delete mLCMThread;

  delete mInternal;
}

void MainWindow::handleCommandLineArgs()
{
  QStringList args = QApplication::instance()->arguments();

  if (args.length() > 1)
  {
    QString filename = args[1];
    this->loadSettings(filename);
  }
  else
  {
    QString settingsFile = QDir::homePath() + "/.signal_scope.json";
    if (QFileInfo(settingsFile).exists())
    {
      this->loadSettings(settingsFile);
    }
  }
}

void MainWindow::onClearHistory()
{
  foreach (PlotWidget* plot, mPlots)
  {
    plot->clearHistory();
  }
}

QString MainWindow::defaultSettingsDir()
{
  QString configDir = qgetenv("DRC_BASE") + "/software/config/signal_scope_configs";
  if (QDir(configDir).exists())
  {
    return QDir(configDir).canonicalPath();
  }
  else
  {
    return QDir::currentPath();
  }
}

void MainWindow::onChooseBackgroundColor()
{
  QStringList colors;
  colors << "Black" << "White";

  bool ok;
  QString color = QInputDialog::getItem(this, "Choose background color", "Color", colors, 0, false, &ok);
  if (ok)
  {
    this->setPlotBackgroundColor(color);
  }
}

void MainWindow::onChoosePointSize()
{
  bool ok;
  int pointSize = QInputDialog::getInt(this, "Choose point size", "Point size", 1, 1, 20, 1, &ok);
  if (ok)
  {
    foreach (PlotWidget* plot, mPlots)
    {
      plot->setPointSize(pointSize - 1);
    }
  }
}

void MainWindow::setPlotBackgroundColor(QString color)
{
  foreach (PlotWidget* plot, mPlots)
  {
    plot->setBackgroundColor(color);
  }
}

void MainWindow::onSyncXAxis(double x0, double x1)
{
  foreach (PlotWidget* plot, mPlots)
  {
    if (plot == this->sender())
      continue;

    plot->setXAxisScale(x0, x1);
    plot->replot();
  }
}

void MainWindow::onRedrawPlots()
{
  mFPSCounter.update();
  //printf("redraw fps: %f\n", this->mFPSCounter.averageFPS());

  if (mPlots.isEmpty())
  {
    return;
  }

  QList<SignalData*> signalDataList;
  foreach (PlotWidget* plot, mPlots)
  {
    foreach (SignalHandler* signalHandler, plot->signalHandlers())
    {
      signalDataList.append(signalHandler->signalData());
    }
  }

  if (signalDataList.isEmpty())
  {
    return;
  }

  float maxTime = std::numeric_limits<float>::min();

  foreach (SignalData* signalData, signalDataList)
  {
    signalData->updateValues();
    if (signalData->size())
    {
      float signalMaxTime = signalData->value(signalData->size() - 1).x();
      if (signalMaxTime > maxTime)
      {
        maxTime = signalMaxTime;
      }
    }
  }

  if (maxTime == std::numeric_limits<float>::min())
  {
    return;
  }

  foreach (PlotWidget* plot, mPlots)
  {
    plot->setEndTime(maxTime);
    plot->replot();
  }
}

void MainWindow::onOpenSettings()
{
  QString filter = "JSON (*.json)";
  QString filename = QFileDialog::getOpenFileName(this, "Open Settings", this->defaultSettingsDir(), filter);
  if (filename.length())
  {
    this->onRemoveAllPlots();
    this->loadSettings(filename);
  }
}

void MainWindow::onSaveSettings()
{
  QString defaultFile = mLastOpenFile.isEmpty() ? this->defaultSettingsDir() : mLastOpenFile;
  QString filter = "JSON (*.json)";
  QString filename = QFileDialog::getSaveFileName(this, "Save Settings", defaultFile, filter);
  if (filename.length())
  {
    this->saveSettings(filename);
  }
}

void MainWindow::saveSettings(const QString& filename)
{
  QMap<QString, QVariant> settings;

  settings["windowWidth"] = this->width();
  settings["windowHeight"] = this->height();

  QList<QVariant> plotSettings;
  foreach (PlotWidget* plot, mPlots)
  {
    plotSettings.append(plot->saveSettings());
  }

  settings["plots"] = plotSettings;

  Json::encodeFile(filename, settings);
}

void MainWindow::loadSettings(const QString& filename)
{
  QMap<QString, QVariant> settings = Json::decodeFile(filename);
  this->loadSettings(settings);
}

void MainWindow::loadSettings(const QMap<QString, QVariant>& settings)
{
  QList<QVariant> plots = settings.value("plots").toList();
  foreach (const QVariant& plot, plots)
  {
    PlotWidget* plotWidget = this->addPlot();
    plotWidget->loadSettings(plot.toMap());
  }

  int windowWidth = settings.value("windowWidth", 1024).toInt();
  int windowHeight = settings.value("windowHeight", 800).toInt();
  this->resize(windowWidth, windowHeight);
}

void MainWindow::onTogglePause()
{
  mPlaying = !mPlaying;
  mInternal->ActionPause->setChecked(mPlaying);
  mInternal->ActionPause->setIcon(qApp->style()->standardIcon(mPlaying ? QStyle::SP_MediaPause : QStyle::SP_MediaPlay));
  mInternal->ActionPause->setText(mPlaying ? "Pause" : "Play");

  foreach (PlotWidget* plot, mPlots)
  {
    if (mPlaying)
      plot->start();
    else
      plot->stop();
  }

  if (mPlaying)
  {
    mRedrawTimer->start(33);
  }
  else
  {
    mRedrawTimer->stop();
  }
}

SignalHandler* MainWindow::getSignalSelectionFromUser()
{
  SelectSignalDialog dialog(this);
  int result = dialog.exec();
  if (result != QDialog::Accepted)
  {
    return 0;
  }

  return dialog.createSignalHandler();
}

void MainWindow::onNewPlotClicked()
{
  SignalHandler* signalHandler = this->getSignalSelectionFromUser();
  if (!signalHandler)
  {
    return;
  }

  PlotWidget* plot = this->addPlot();
  plot->addSignal(signalHandler);
}

PlotWidget* MainWindow::addPlot()
{
  PlotWidget* plot = new PlotWidget(mLCMThread);
  mPlotLayout->addWidget(plot);
  this->connect(plot, SIGNAL(removePlotRequested(PlotWidget*)), SLOT(onRemovePlot(PlotWidget*)));
  this->connect(plot, SIGNAL(addSignalRequested(PlotWidget*)), SLOT(onAddSignalToPlot(PlotWidget*)));
  this->connect(plot, SIGNAL(syncXAxisScale(double, double)), SLOT(onSyncXAxis(double, double)));
  mPlots.append(plot);
  return plot;
}

void MainWindow::onAddSignalToPlot(PlotWidget* plot)
{
  if (!plot)
  {
    return;
  }

  SignalHandler* signalHandler = this->getSignalSelectionFromUser();
  if (!signalHandler)
  {
    return;
  }

  plot->addSignal(signalHandler);
}

void MainWindow::onRemoveAllPlots()
{
  QList<PlotWidget*> plots = mPlots;
  foreach(PlotWidget* plot, plots)
  {
    this->onRemovePlot(plot);
  }
}

void MainWindow::onRemovePlot(PlotWidget* plot)
{
  if (!plot)
  {
    return;
  }

  mPlotLayout->removeWidget(plot);
  mPlots.removeAll(plot);
  delete plot;
}
<commit_msg>signal_scope: replace activated() with triggered()<commit_after>#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "plotwidget.h"
#include "signalhandler.h"
#include "signaldata.h"
#include "selectsignaldialog.h"
#include "signaldescription.h"
#include "lcmthread.h"

#include <QLabel>
#include <QLayout>
#include <QApplication>
#include <QDebug>
#include <QScrollArea>
#include <QPushButton>
#include <QShortcut>
#include <QFileDialog>
#include <QInputDialog>
#include <QTimer>

#include "qjson.h"

#include <cstdio>
#include <limits>

class MainWindow::Internal : public Ui::MainWindow
{
public:

};

MainWindow::MainWindow(QWidget* parent): QMainWindow(parent)
{
  mInternal = new Internal;
  mInternal->setupUi(this);

  mPlaying = false;
  this->setWindowTitle("Signal Scope");

  mLCMThread = new LCMThread;
  mLCMThread->start();

  mScrollArea = new QScrollArea;
  mPlotArea = new QWidget;
  mPlotLayout = new QVBoxLayout(mPlotArea);

  mScrollArea->setWidget(mPlotArea);
  mScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  mScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
  mScrollArea->setWidgetResizable(true);
  this->setCentralWidget(mScrollArea);

  mInternal->ActionOpen->setIcon(qApp->style()->standardIcon(QStyle::SP_DialogOpenButton));
  mInternal->ActionSave->setIcon(qApp->style()->standardIcon(QStyle::SP_DialogSaveButton));
  mInternal->ActionPause->setIcon(qApp->style()->standardIcon(QStyle::SP_MediaPlay));
  mInternal->ActionClearHistory->setIcon(qApp->style()->standardIcon(QStyle::SP_TrashIcon));
  mInternal->ActionAddPlot->setIcon(qApp->style()->standardIcon(QStyle::SP_TrashIcon));
  //QStyle::SP_DialogDiscardButton

  this->connect(mInternal->ActionQuit, SIGNAL(triggered()), SLOT(close()));
  this->connect(mInternal->ActionOpen, SIGNAL(triggered()), SLOT(onOpenSettings()));
  this->connect(mInternal->ActionSave, SIGNAL(triggered()), SLOT(onSaveSettings()));
  this->connect(mInternal->ActionPause, SIGNAL(triggered()), SLOT(onTogglePause()));
  this->connect(mInternal->ActionAddPlot, SIGNAL(triggered()), SLOT(onNewPlotClicked()));
  this->connect(mInternal->ActionClearHistory, SIGNAL(triggered()), SLOT(onClearHistory()));

  this->connect(mInternal->ActionBackgroundColor, SIGNAL(triggered()), SLOT(onChooseBackgroundColor()));
  this->connect(mInternal->ActionPointSize, SIGNAL(triggered()), SLOT(onChoosePointSize()));

  mRedrawTimer = new QTimer(this);
  //mRedrawTimer->setSingleShot(true);
  this->connect(mRedrawTimer, SIGNAL(timeout()), this, SLOT(onRedrawPlots()));

  this->resize(1024,800);
  this->handleCommandLineArgs();

  this->onTogglePause();
}

MainWindow::~MainWindow()
{

  QString settingsFile = QDir::homePath() + "/.signal_scope.json";
  this->saveSettings(settingsFile);

  mLCMThread->stop();
  mLCMThread->wait(250);
  delete mLCMThread;

  delete mInternal;
}

void MainWindow::handleCommandLineArgs()
{
  QStringList args = QApplication::instance()->arguments();

  if (args.length() > 1)
  {
    QString filename = args[1];
    this->loadSettings(filename);
  }
  else
  {
    QString settingsFile = QDir::homePath() + "/.signal_scope.json";
    if (QFileInfo(settingsFile).exists())
    {
      this->loadSettings(settingsFile);
    }
  }
}

void MainWindow::onClearHistory()
{
  foreach (PlotWidget* plot, mPlots)
  {
    plot->clearHistory();
  }
}

QString MainWindow::defaultSettingsDir()
{
  QString configDir = qgetenv("DRC_BASE") + "/software/config/signal_scope_configs";
  if (QDir(configDir).exists())
  {
    return QDir(configDir).canonicalPath();
  }
  else
  {
    return QDir::currentPath();
  }
}

void MainWindow::onChooseBackgroundColor()
{
  QStringList colors;
  colors << "Black" << "White";

  bool ok;
  QString color = QInputDialog::getItem(this, "Choose background color", "Color", colors, 0, false, &ok);
  if (ok)
  {
    this->setPlotBackgroundColor(color);
  }
}

void MainWindow::onChoosePointSize()
{
  bool ok;
  int pointSize = QInputDialog::getInt(this, "Choose point size", "Point size", 1, 1, 20, 1, &ok);
  if (ok)
  {
    foreach (PlotWidget* plot, mPlots)
    {
      plot->setPointSize(pointSize - 1);
    }
  }
}

void MainWindow::setPlotBackgroundColor(QString color)
{
  foreach (PlotWidget* plot, mPlots)
  {
    plot->setBackgroundColor(color);
  }
}

void MainWindow::onSyncXAxis(double x0, double x1)
{
  foreach (PlotWidget* plot, mPlots)
  {
    if (plot == this->sender())
      continue;

    plot->setXAxisScale(x0, x1);
    plot->replot();
  }
}

void MainWindow::onRedrawPlots()
{
  mFPSCounter.update();
  //printf("redraw fps: %f\n", this->mFPSCounter.averageFPS());

  if (mPlots.isEmpty())
  {
    return;
  }

  QList<SignalData*> signalDataList;
  foreach (PlotWidget* plot, mPlots)
  {
    foreach (SignalHandler* signalHandler, plot->signalHandlers())
    {
      signalDataList.append(signalHandler->signalData());
    }
  }

  if (signalDataList.isEmpty())
  {
    return;
  }

  float maxTime = std::numeric_limits<float>::min();

  foreach (SignalData* signalData, signalDataList)
  {
    signalData->updateValues();
    if (signalData->size())
    {
      float signalMaxTime = signalData->value(signalData->size() - 1).x();
      if (signalMaxTime > maxTime)
      {
        maxTime = signalMaxTime;
      }
    }
  }

  if (maxTime == std::numeric_limits<float>::min())
  {
    return;
  }

  foreach (PlotWidget* plot, mPlots)
  {
    plot->setEndTime(maxTime);
    plot->replot();
  }
}

void MainWindow::onOpenSettings()
{
  QString filter = "JSON (*.json)";
  QString filename = QFileDialog::getOpenFileName(this, "Open Settings", this->defaultSettingsDir(), filter);
  if (filename.length())
  {
    this->onRemoveAllPlots();
    this->loadSettings(filename);
  }
}

void MainWindow::onSaveSettings()
{
  QString defaultFile = mLastOpenFile.isEmpty() ? this->defaultSettingsDir() : mLastOpenFile;
  QString filter = "JSON (*.json)";
  QString filename = QFileDialog::getSaveFileName(this, "Save Settings", defaultFile, filter);
  if (filename.length())
  {
    this->saveSettings(filename);
  }
}

void MainWindow::saveSettings(const QString& filename)
{
  QMap<QString, QVariant> settings;

  settings["windowWidth"] = this->width();
  settings["windowHeight"] = this->height();

  QList<QVariant> plotSettings;
  foreach (PlotWidget* plot, mPlots)
  {
    plotSettings.append(plot->saveSettings());
  }

  settings["plots"] = plotSettings;

  Json::encodeFile(filename, settings);
}

void MainWindow::loadSettings(const QString& filename)
{
  QMap<QString, QVariant> settings = Json::decodeFile(filename);
  this->loadSettings(settings);
}

void MainWindow::loadSettings(const QMap<QString, QVariant>& settings)
{
  QList<QVariant> plots = settings.value("plots").toList();
  foreach (const QVariant& plot, plots)
  {
    PlotWidget* plotWidget = this->addPlot();
    plotWidget->loadSettings(plot.toMap());
  }

  int windowWidth = settings.value("windowWidth", 1024).toInt();
  int windowHeight = settings.value("windowHeight", 800).toInt();
  this->resize(windowWidth, windowHeight);
}

void MainWindow::onTogglePause()
{
  mPlaying = !mPlaying;
  mInternal->ActionPause->setChecked(mPlaying);
  mInternal->ActionPause->setIcon(qApp->style()->standardIcon(mPlaying ? QStyle::SP_MediaPause : QStyle::SP_MediaPlay));
  mInternal->ActionPause->setText(mPlaying ? "Pause" : "Play");

  foreach (PlotWidget* plot, mPlots)
  {
    if (mPlaying)
      plot->start();
    else
      plot->stop();
  }

  if (mPlaying)
  {
    mRedrawTimer->start(33);
  }
  else
  {
    mRedrawTimer->stop();
  }
}

SignalHandler* MainWindow::getSignalSelectionFromUser()
{
  SelectSignalDialog dialog(this);
  int result = dialog.exec();
  if (result != QDialog::Accepted)
  {
    return 0;
  }

  return dialog.createSignalHandler();
}

void MainWindow::onNewPlotClicked()
{
  SignalHandler* signalHandler = this->getSignalSelectionFromUser();
  if (!signalHandler)
  {
    return;
  }

  PlotWidget* plot = this->addPlot();
  plot->addSignal(signalHandler);
}

PlotWidget* MainWindow::addPlot()
{
  PlotWidget* plot = new PlotWidget(mLCMThread);
  mPlotLayout->addWidget(plot);
  this->connect(plot, SIGNAL(removePlotRequested(PlotWidget*)), SLOT(onRemovePlot(PlotWidget*)));
  this->connect(plot, SIGNAL(addSignalRequested(PlotWidget*)), SLOT(onAddSignalToPlot(PlotWidget*)));
  this->connect(plot, SIGNAL(syncXAxisScale(double, double)), SLOT(onSyncXAxis(double, double)));
  mPlots.append(plot);
  return plot;
}

void MainWindow::onAddSignalToPlot(PlotWidget* plot)
{
  if (!plot)
  {
    return;
  }

  SignalHandler* signalHandler = this->getSignalSelectionFromUser();
  if (!signalHandler)
  {
    return;
  }

  plot->addSignal(signalHandler);
}

void MainWindow::onRemoveAllPlots()
{
  QList<PlotWidget*> plots = mPlots;
  foreach(PlotWidget* plot, plots)
  {
    this->onRemovePlot(plot);
  }
}

void MainWindow::onRemovePlot(PlotWidget* plot)
{
  if (!plot)
  {
    return;
  }

  mPlotLayout->removeWidget(plot);
  mPlots.removeAll(plot);
  delete plot;
}
<|endoftext|>


<commit_before>#include "pch.h"
#include <thread>
#include "TcpClient.h"
#include "platform/CCFileUtils.h"
#include "base/CCDirector.h"
#include "base/CCScheduler.h"
#include "2d/CCLabel.h"
#include "PacketType.h"
#include "SingleGameScene.h"
#include "MultiGameScene.h"
#include "NetworkScene.h"
#include "RoomScene.h"
#include "ObjectLayer.h"
#include "LoadingBGLayer.h"

#ifdef _WIN32
#pragma comment(lib,"ws2_32.lib")
#define sleep(x) Sleep(x)
#endif

static TcpClient* s_TcpClient = nullptr;

TcpClient::TcpClient() : mRecvBuffer(BUF_SIZE), mSock(NULL), mLoginId(-1)
{
	///
	auto t = std::thread(CC_CALLBACK_0(TcpClient::networkThread, this));
	t.detach();
}

TcpClient::~TcpClient()
{
	if(mSock == NULL)
		return;

#ifndef _WIN32
	close(mSock);
#else
	closesocket(mSock);
	WSACleanup();
#endif
}

TcpClient* TcpClient::getInstance()
{
	if (nullptr == s_TcpClient)
	{
		s_TcpClient = new TcpClient();
	}
	return s_TcpClient;
}

void TcpClient::destroyInstance()
{
	CC_SAFE_DELETE(s_TcpClient);
}

///////////////////////////////////////////////////////////////////////////
/*
	 ,  Լ
*/
///////////////////////////////////////////////////////////////////////////
bool TcpClient::connect()
{
	if (mSock != NULL)
	{
		TcpClient::getInstance()->disconnect();
	}

#ifdef _WIN32
	WSADATA wsa;
	if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
		return false;
#endif

	mSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (mSock == INVALID_SOCKET)
		return false;

	std::string ipaddr = cocos2d::UserDefault::getInstance()->getStringForKey("ipaddr", std::string("localhost"));
	int port = cocos2d::UserDefault::getInstance()->getIntegerForKey("port", 9001);

	struct hostent* host;
	struct sockaddr_in hostAddr;

	if ((host = gethostbyname(ipaddr.c_str())) == 0)
		return false;

	memset(&hostAddr, 0, sizeof(hostAddr));
	hostAddr.sin_family = AF_INET;
	hostAddr.sin_addr.s_addr = inet_addr("10.73.39.104");
	hostAddr.sin_port = htons(port);

	if (SOCKET_ERROR == ::connect(mSock, (struct sockaddr*)&hostAddr, sizeof(hostAddr)))
	{
		CCLOG("CONNECT FAILED");
		return false;
	}

	/// nagle ˰
	int opt = 1;
	setsockopt(mSock, IPPROTO_TCP, TCP_NODELAY, (const char*)&opt, sizeof(int));

	return true;
}

void TcpClient::disconnect()
{
	if (mSock == NULL)
		return;

#ifndef _WIN32
	close(mSock);
#else
	closesocket(mSock);
	WSACleanup();
#endif
	mSock = NULL;
	mLoginId = -1;

	return;
}

///////////////////////////////////////////////////////////////////////////
/*
	 Ŷ , ޴ Լ
*/
///////////////////////////////////////////////////////////////////////////
bool TcpClient::send(const char* data, int length)
{
	int count = 0;
	while (count < length)
	{
		int n = ::send(mSock, data + count, length, 0);
		if (n == SOCKET_ERROR)
		{
			CCLOG("SEND ERROR");
			return false;
		}
		count += n;
		length -= n;
	}

	return true;
}

void TcpClient::networkThread()
{
	while ( true )
	{
		char inBuf[4096] = { 0, };

		int n = ::recv(mSock, inBuf, 4096, 0);

		if (n < 1)
		{
			sleep(0); ///< for cpu low-utilization
			continue;
		}

		if (!mRecvBuffer.Write(inBuf, n))
		{
			///  á.
			assert(false);
		}

		processPacket();
	}
}

///////////////////////////////////////////////////////////////////////////
/*
	 Ŷ ĽϿ óϴ Լ
*/
///////////////////////////////////////////////////////////////////////////
void TcpClient::processPacket()
{
	auto scheduler = cocos2d::Director::getInstance()->getScheduler();

	/// Ŷ Ľؼ ϼǴ Ŷ , ش ݹ ҷش.
	while (true)
	{
		PacketHeader header;

		if (false == mRecvBuffer.Peek((char*)&header, sizeof(PacketHeader)))
			break;

		if (header.mSize > mRecvBuffer.GetStoredSize())
			break;

		switch (header.mType)
		{
		case PKT_SC_LOGIN:
			{
				LoginResult recvData;
				bool ret = mRecvBuffer.Read((char*)&recvData, recvData.mSize);
				assert(ret && recvData.mPlayerId != -1);

				mLoginId = recvData.mPlayerId;

				auto scene = GET_NETWORK_SCENE;		assert(scene != nullptr);
				scheduler->performFunctionInCocosThread(CC_CALLBACK_0(NetworkScene::ConnectLabelChange, scene,
					"  !!"));
			}
			break;

		case PKT_SC_MAKE_ROOM:
			{
				MakeRoomResult recvData;
				bool ret = mRecvBuffer.Read((char*)&recvData, recvData.mSize);
				assert(ret && recvData.mPlayerId == mLoginId);

				auto scene = GET_NETWORK_SCENE;		assert(scene != nullptr);
				scheduler->performFunctionInCocosThread(CC_CALLBACK_0(NetworkScene::MakeRoomComplete, scene,
					recvData.mRoomId));
			}
			break;

		case PKT_SC_INOUT_ROOM:
			{
				InOutRoomResult recvData;
				bool ret = mRecvBuffer.Read((char*)&recvData, recvData.mSize);
				assert(ret && recvData.mPlayerId == mLoginId);

				if (recvData.mIsIn)
				{
					auto scene = GET_NETWORK_SCENE;	assert(scene != nullptr);
					scheduler->performFunctionInCocosThread(CC_CALLBACK_0(NetworkScene::JoinRoomComplete, scene,
						recvData.mRoomId));
				}
				else
				{
					// ÷̾ ó ʿ
				}
			}
			break;

		case PKT_SC_ALL_READY:
			{
				GameRunNotify recvData;
				bool ret = mRecvBuffer.Read((char*)&recvData, recvData.mSize);
				assert(ret && recvData.mPlayerId != -1);

				auto scene = GET_ROOM_SCENE;		assert(scene != nullptr);
				scheduler->performFunctionInCocosThread(CC_CALLBACK_0(RoomScene::GameStartComplete, scene));
			}
			return; //   Ŷ   ݹԼ ȣ ʿϹǷ

		case PKT_SC_CREATE_HERO:
			{
				CreateHeroResult recvData;
				bool ret = mRecvBuffer.Read((char*)&recvData, recvData.mSize);
				assert(ret && recvData.mPlayerId != -1);

				auto pos = Point(recvData.mPosX, recvData.mPosY);

				auto layer = GET_OBJECT_LAYER;		assert(layer != nullptr);
				scheduler->performFunctionInCocosThread(CC_CALLBACK_0(ObjectLayer::FirstDrawUnit, layer,
					recvData.mPlayerId, recvData.mUnitId, recvData.mUnitType, pos));
			}
			break;

		case PKT_SC_RUN_COMPLETE:
			{
				ServerRunCompleteNotify recvData;
				bool ret = mRecvBuffer.Read((char*)&recvData, recvData.mSize);
				assert(ret && recvData.mPlayerId != -1);

				auto layer = GET_LOADING_LAYER;		assert(layer != nullptr);
				scheduler->performFunctionInCocosThread(CC_CALLBACK_0(LoadingBGLayer::SetLoadingFin, layer));
			}
			return; //   Ŷ   ݹԼ ȣ ʿϹǷ

		case PKT_SC_START_GAME:
			{
				StartGameNotify recvData;
				bool ret = mRecvBuffer.Read((char*)&recvData, recvData.mSize);
				assert(ret && recvData.mPlayerId != -1);

				auto scene = GET_M_GAME_SCENE;		assert(scene != nullptr);
				scheduler->performFunctionInCocosThread(CC_CALLBACK_0(MultiGameScene::StartGame, scene));
			}
			break;

		case PKT_SC_MOVE:
			{
				MoveBroadcastResult recvData;
				bool ret = mRecvBuffer.Read((char*)&recvData, recvData.mSize);
				assert(ret && recvData.mPlayerId != -1);

				auto curPos = Point(recvData.mCurrentPosX, recvData.mCurrentPosY);
				auto targetPos = Point(recvData.mTargetPosX, recvData.mTargetPosY);

				auto layer = GET_OBJECT_LAYER;		assert(layer != nullptr);
				scheduler->performFunctionInCocosThread(CC_CALLBACK_0(ObjectLayer::UnitMove, layer,
					recvData.mUnitId, curPos, targetPos));
			}
			break;

		case PKT_SC_CRASH:
			{
				CrashedBroadcastResult recvData;
				bool ret = mRecvBuffer.Read((char*)&recvData, recvData.mSize);
				assert(ret && recvData.mPlayerId != -1);

				auto exPos = Point(recvData.mExpectPosX, recvData.mExpectPosY);
				auto revisionPos = Point(recvData.mCurrentPosX, recvData.mCurrentPosY);

				auto layer = GET_OBJECT_LAYER;		assert(layer != nullptr);
				scheduler->performFunctionInCocosThread(CC_CALLBACK_0(ObjectLayer::UnitCrash, layer,
					recvData.mUnitId, exPos));

				if (!recvData.mIsCrashed)
				{
					scheduler->performFunctionInCocosThread(CC_CALLBACK_0(ObjectLayer::UnitCrashEnd, layer,
						recvData.mUnitId, revisionPos));
				}
			}
			break;

		case PKT_SC_SKILL:
			{
				SkillBroadcastResult recvData;
				bool ret = mRecvBuffer.Read((char*)&recvData, recvData.mSize);
				assert(ret && recvData.mPlayerId != -1);

				auto curPos = Point(recvData.mCurrentPosX, recvData.mCurrentPosY);
				auto targetPos = Point(recvData.mTargetPosX, recvData.mTargetPosY);

				auto layer = GET_OBJECT_LAYER;		assert(layer != nullptr);
				scheduler->performFunctionInCocosThread(CC_CALLBACK_0(ObjectLayer::UnitSkillUse, layer,
					recvData.mUnitId, recvData.mKey, curPos, targetPos));
			}
			break;

		default:
			assert(false);
		}

	}
}

///////////////////////////////////////////////////////////////////////////
/*
	 Ŷ Ľϴ Լ
*/
///////////////////////////////////////////////////////////////////////////
void TcpClient::loginRequest()
{
	if (mLoginId > 0)
		return;

	srand(time(NULL));

	LoginRequest sendData;
	sendData.mPlayerId = 1000 + rand() % 101;	// ̵ ӽ÷

	send((const char*)&sendData, sizeof(LoginRequest));
}

void TcpClient::makeRoomRequest()
{
	if (mLoginId < 0)
		return;

	MakeRoomRequest sendData;
	sendData.mPlayerId = mLoginId;

	send((const char*)&sendData, sizeof(MakeRoomRequest));
}

void TcpClient::joinRoomRequest()
{
	if (mLoginId < 0)
		return;

	InOutRoomRequest sendData;
	sendData.mPlayerId = mLoginId;
	sendData.mIsIn = true;

	send((const char*)&sendData, sizeof(InOutRoomRequest));
}

void TcpClient::outRoomRequest(int roomId)
{
	if (mLoginId < 0)
		return;

	InOutRoomRequest sendData;
	sendData.mPlayerId = mLoginId;
	sendData.mIsIn = false;
	sendData.mRoomId = roomId;

	send((const char*)&sendData, sizeof(InOutRoomRequest));
}

void TcpClient::startGameRequest()
{
	if (mLoginId < 0)
		return;

	GameReadyNotify sendData;
	sendData.mPlayerId = mLoginId;
<<<<<<< HEAD
=======
	sendData.mHeroType = HERO_MAGICIAN;

>>>>>>> origin/v0.3_Skill_Make
	send((const char*)&sendData, sizeof(GameReadyNotify));
}

void TcpClient::runCompleteRequest()
{
	if (mLoginId < 0)
		return;

	ClientRunCompleteNotify sendData;
	sendData.mPlayerId = mLoginId;

	send((const char*)&sendData, sizeof(ClientRunCompleteNotify));
}

void TcpClient::moveRequest(Point curPos, Point targetPos)
{
	if (mLoginId < 0)
		return;

	MoveRequest sendData;
	sendData.mPlayerId = mLoginId;
	sendData.mCurrentPosX = curPos.x;
	sendData.mCurrentPosY = curPos.y;
	sendData.mTargetPosX = targetPos.x;
	sendData.mTargetPosY = targetPos.y;

	send((const char*)&sendData, sizeof(MoveRequest));
}

void TcpClient::skillRequest(Point curPos, Point targetPos, SkillKey skillKey)
{
	if (mLoginId < 0)
		return;

	SkillRequest sendData;
	sendData.mPlayerId = mLoginId;
	sendData.mCurrentPosX = curPos.x;
	sendData.mCurrentPosY = curPos.y;
	sendData.mTargetPosX = targetPos.x;
	sendData.mTargetPosY = targetPos.y;
	sendData.mKey = skillKey;

	send((const char*)&sendData, sizeof(SkillRequest));
}

//  void TcpClient::chatRequest(const char* chat)
//  {
// 	 if (mLoginId < 0)
// 		 return;
//
// 	 ChatBroadcastRequest sendData;
//
// 	 sendData.mPlayerId = mLoginId;
// 	 memcpy(sendData.mChat, chat, strlen(chat));
//
// 	 send((const char*)&sendData, sizeof(ChatBroadcastRequest));
//  }
//
<commit_msg>[C] conflict 해결<commit_after>#include "pch.h"
#include <thread>
#include "TcpClient.h"
#include "platform/CCFileUtils.h"
#include "base/CCDirector.h"
#include "base/CCScheduler.h"
#include "2d/CCLabel.h"
#include "PacketType.h"
#include "SingleGameScene.h"
#include "MultiGameScene.h"
#include "NetworkScene.h"
#include "RoomScene.h"
#include "ObjectLayer.h"
#include "LoadingBGLayer.h"

#ifdef _WIN32
#pragma comment(lib,"ws2_32.lib")
#define sleep(x) Sleep(x)
#endif

static TcpClient* s_TcpClient = nullptr;

TcpClient::TcpClient() : mRecvBuffer(BUF_SIZE), mSock(NULL), mLoginId(-1)
{
	///
	auto t = std::thread(CC_CALLBACK_0(TcpClient::networkThread, this));
	t.detach();
}

TcpClient::~TcpClient()
{
	if(mSock == NULL)
		return;

#ifndef _WIN32
	close(mSock);
#else
	closesocket(mSock);
	WSACleanup();
#endif
}

TcpClient* TcpClient::getInstance()
{
	if (nullptr == s_TcpClient)
	{
		s_TcpClient = new TcpClient();
	}
	return s_TcpClient;
}

void TcpClient::destroyInstance()
{
	CC_SAFE_DELETE(s_TcpClient);
}

///////////////////////////////////////////////////////////////////////////
/*
	 ,  Լ
*/
///////////////////////////////////////////////////////////////////////////
bool TcpClient::connect()
{
	if (mSock != NULL)
	{
		TcpClient::getInstance()->disconnect();
	}

#ifdef _WIN32
	WSADATA wsa;
	if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
		return false;
#endif

	mSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (mSock == INVALID_SOCKET)
		return false;

	std::string ipaddr = cocos2d::UserDefault::getInstance()->getStringForKey("ipaddr", std::string("localhost"));
	int port = cocos2d::UserDefault::getInstance()->getIntegerForKey("port", 9001);

	struct hostent* host;
	struct sockaddr_in hostAddr;

	if ((host = gethostbyname(ipaddr.c_str())) == 0)
		return false;

	memset(&hostAddr, 0, sizeof(hostAddr));
	hostAddr.sin_family = AF_INET;
	hostAddr.sin_addr.s_addr = inet_addr("10.73.39.104");
	hostAddr.sin_port = htons(port);

	if (SOCKET_ERROR == ::connect(mSock, (struct sockaddr*)&hostAddr, sizeof(hostAddr)))
	{
		CCLOG("CONNECT FAILED");
		return false;
	}

	/// nagle ˰
	int opt = 1;
	setsockopt(mSock, IPPROTO_TCP, TCP_NODELAY, (const char*)&opt, sizeof(int));

	return true;
}

void TcpClient::disconnect()
{
	if (mSock == NULL)
		return;

#ifndef _WIN32
	close(mSock);
#else
	closesocket(mSock);
	WSACleanup();
#endif
	mSock = NULL;
	mLoginId = -1;

	return;
}

///////////////////////////////////////////////////////////////////////////
/*
	 Ŷ , ޴ Լ
*/
///////////////////////////////////////////////////////////////////////////
bool TcpClient::send(const char* data, int length)
{
	int count = 0;
	while (count < length)
	{
		int n = ::send(mSock, data + count, length, 0);
		if (n == SOCKET_ERROR)
		{
			CCLOG("SEND ERROR");
			return false;
		}
		count += n;
		length -= n;
	}

	return true;
}

void TcpClient::networkThread()
{
	while ( true )
	{
		char inBuf[4096] = { 0, };

		int n = ::recv(mSock, inBuf, 4096, 0);

		if (n < 1)
		{
			sleep(0); ///< for cpu low-utilization
			continue;
		}

		if (!mRecvBuffer.Write(inBuf, n))
		{
			///  á.
			assert(false);
		}

		processPacket();
	}
}

///////////////////////////////////////////////////////////////////////////
/*
	 Ŷ ĽϿ óϴ Լ
*/
///////////////////////////////////////////////////////////////////////////
void TcpClient::processPacket()
{
	auto scheduler = cocos2d::Director::getInstance()->getScheduler();

	/// Ŷ Ľؼ ϼǴ Ŷ , ش ݹ ҷش.
	while (true)
	{
		PacketHeader header;

		if (false == mRecvBuffer.Peek((char*)&header, sizeof(PacketHeader)))
			break;

		if (header.mSize > mRecvBuffer.GetStoredSize())
			break;

		switch (header.mType)
		{
		case PKT_SC_LOGIN:
			{
				LoginResult recvData;
				bool ret = mRecvBuffer.Read((char*)&recvData, recvData.mSize);
				assert(ret && recvData.mPlayerId != -1);

				mLoginId = recvData.mPlayerId;

				auto scene = GET_NETWORK_SCENE;		assert(scene != nullptr);
				scheduler->performFunctionInCocosThread(CC_CALLBACK_0(NetworkScene::ConnectLabelChange, scene,
					"  !!"));
			}
			break;

		case PKT_SC_MAKE_ROOM:
			{
				MakeRoomResult recvData;
				bool ret = mRecvBuffer.Read((char*)&recvData, recvData.mSize);
				assert(ret && recvData.mPlayerId == mLoginId);

				auto scene = GET_NETWORK_SCENE;		assert(scene != nullptr);
				scheduler->performFunctionInCocosThread(CC_CALLBACK_0(NetworkScene::MakeRoomComplete, scene,
					recvData.mRoomId));
			}
			break;

		case PKT_SC_INOUT_ROOM:
			{
				InOutRoomResult recvData;
				bool ret = mRecvBuffer.Read((char*)&recvData, recvData.mSize);
				assert(ret && recvData.mPlayerId == mLoginId);

				if (recvData.mIsIn)
				{
					auto scene = GET_NETWORK_SCENE;	assert(scene != nullptr);
					scheduler->performFunctionInCocosThread(CC_CALLBACK_0(NetworkScene::JoinRoomComplete, scene,
						recvData.mRoomId));
				}
				else
				{
					// ÷̾ ó ʿ
				}
			}
			break;

		case PKT_SC_ALL_READY:
			{
				GameRunNotify recvData;
				bool ret = mRecvBuffer.Read((char*)&recvData, recvData.mSize);
				assert(ret && recvData.mPlayerId != -1);

				auto scene = GET_ROOM_SCENE;		assert(scene != nullptr);
				scheduler->performFunctionInCocosThread(CC_CALLBACK_0(RoomScene::GameStartComplete, scene));
			}
			return; //   Ŷ   ݹԼ ȣ ʿϹǷ

		case PKT_SC_CREATE_HERO:
			{
				CreateHeroResult recvData;
				bool ret = mRecvBuffer.Read((char*)&recvData, recvData.mSize);
				assert(ret && recvData.mPlayerId != -1);

				auto pos = Point(recvData.mPosX, recvData.mPosY);

				auto layer = GET_OBJECT_LAYER;		assert(layer != nullptr);
				scheduler->performFunctionInCocosThread(CC_CALLBACK_0(ObjectLayer::FirstDrawUnit, layer,
					recvData.mPlayerId, recvData.mUnitId, recvData.mUnitType, pos));
			}
			break;

		case PKT_SC_RUN_COMPLETE:
			{
				ServerRunCompleteNotify recvData;
				bool ret = mRecvBuffer.Read((char*)&recvData, recvData.mSize);
				assert(ret && recvData.mPlayerId != -1);

				auto layer = GET_LOADING_LAYER;		assert(layer != nullptr);
				scheduler->performFunctionInCocosThread(CC_CALLBACK_0(LoadingBGLayer::SetLoadingFin, layer));
			}
			return; //   Ŷ   ݹԼ ȣ ʿϹǷ

		case PKT_SC_START_GAME:
			{
				StartGameNotify recvData;
				bool ret = mRecvBuffer.Read((char*)&recvData, recvData.mSize);
				assert(ret && recvData.mPlayerId != -1);

				auto scene = GET_M_GAME_SCENE;		assert(scene != nullptr);
				scheduler->performFunctionInCocosThread(CC_CALLBACK_0(MultiGameScene::StartGame, scene));
			}
			break;

		case PKT_SC_MOVE:
			{
				MoveBroadcastResult recvData;
				bool ret = mRecvBuffer.Read((char*)&recvData, recvData.mSize);
				assert(ret && recvData.mPlayerId != -1);

				auto curPos = Point(recvData.mCurrentPosX, recvData.mCurrentPosY);
				auto targetPos = Point(recvData.mTargetPosX, recvData.mTargetPosY);

				auto layer = GET_OBJECT_LAYER;		assert(layer != nullptr);
				scheduler->performFunctionInCocosThread(CC_CALLBACK_0(ObjectLayer::UnitMove, layer,
					recvData.mUnitId, curPos, targetPos));
			}
			break;

		case PKT_SC_CRASH:
			{
				CrashedBroadcastResult recvData;
				bool ret = mRecvBuffer.Read((char*)&recvData, recvData.mSize);
				assert(ret && recvData.mPlayerId != -1);

				auto exPos = Point(recvData.mExpectPosX, recvData.mExpectPosY);
				auto revisionPos = Point(recvData.mCurrentPosX, recvData.mCurrentPosY);

				auto layer = GET_OBJECT_LAYER;		assert(layer != nullptr);
				scheduler->performFunctionInCocosThread(CC_CALLBACK_0(ObjectLayer::UnitCrash, layer,
					recvData.mUnitId, exPos));

				if (!recvData.mIsCrashed)
				{
					scheduler->performFunctionInCocosThread(CC_CALLBACK_0(ObjectLayer::UnitCrashEnd, layer,
						recvData.mUnitId, revisionPos));
				}
			}
			break;

		case PKT_SC_SKILL:
			{
				SkillBroadcastResult recvData;
				bool ret = mRecvBuffer.Read((char*)&recvData, recvData.mSize);
				assert(ret && recvData.mPlayerId != -1);

				auto curPos = Point(recvData.mCurrentPosX, recvData.mCurrentPosY);
				auto targetPos = Point(recvData.mTargetPosX, recvData.mTargetPosY);

				auto layer = GET_OBJECT_LAYER;		assert(layer != nullptr);
				scheduler->performFunctionInCocosThread(CC_CALLBACK_0(ObjectLayer::UnitSkillUse, layer,
					recvData.mUnitId, recvData.mKey, curPos, targetPos));
			}
			break;

		default:
			assert(false);
		}

	}
}

///////////////////////////////////////////////////////////////////////////
/*
	 Ŷ Ľϴ Լ
*/
///////////////////////////////////////////////////////////////////////////
void TcpClient::loginRequest()
{
	if (mLoginId > 0)
		return;

	srand(time(NULL));

	LoginRequest sendData;
	sendData.mPlayerId = 1000 + rand() % 101;	// ̵ ӽ÷

	send((const char*)&sendData, sizeof(LoginRequest));
}

void TcpClient::makeRoomRequest()
{
	if (mLoginId < 0)
		return;

	MakeRoomRequest sendData;
	sendData.mPlayerId = mLoginId;

	send((const char*)&sendData, sizeof(MakeRoomRequest));
}

void TcpClient::joinRoomRequest()
{
	if (mLoginId < 0)
		return;

	InOutRoomRequest sendData;
	sendData.mPlayerId = mLoginId;
	sendData.mIsIn = true;

	send((const char*)&sendData, sizeof(InOutRoomRequest));
}

void TcpClient::outRoomRequest(int roomId)
{
	if (mLoginId < 0)
		return;

	InOutRoomRequest sendData;
	sendData.mPlayerId = mLoginId;
	sendData.mIsIn = false;
	sendData.mRoomId = roomId;

	send((const char*)&sendData, sizeof(InOutRoomRequest));
}

void TcpClient::startGameRequest()
{
	if (mLoginId < 0)
		return;

	GameReadyNotify sendData;
	sendData.mPlayerId = mLoginId;
	sendData.mHeroType = HERO_MAGICIAN;

	send((const char*)&sendData, sizeof(GameReadyNotify));
}

void TcpClient::runCompleteRequest()
{
	if (mLoginId < 0)
		return;

	ClientRunCompleteNotify sendData;
	sendData.mPlayerId = mLoginId;

	send((const char*)&sendData, sizeof(ClientRunCompleteNotify));
}

void TcpClient::moveRequest(Point curPos, Point targetPos)
{
	if (mLoginId < 0)
		return;

	MoveRequest sendData;
	sendData.mPlayerId = mLoginId;
	sendData.mCurrentPosX = curPos.x;
	sendData.mCurrentPosY = curPos.y;
	sendData.mTargetPosX = targetPos.x;
	sendData.mTargetPosY = targetPos.y;

	send((const char*)&sendData, sizeof(MoveRequest));
}

void TcpClient::skillRequest(Point curPos, Point targetPos, SkillKey skillKey)
{
	if (mLoginId < 0)
		return;

	SkillRequest sendData;
	sendData.mPlayerId = mLoginId;
	sendData.mCurrentPosX = curPos.x;
	sendData.mCurrentPosY = curPos.y;
	sendData.mTargetPosX = targetPos.x;
	sendData.mTargetPosY = targetPos.y;
	sendData.mKey = skillKey;

	send((const char*)&sendData, sizeof(SkillRequest));
}

//  void TcpClient::chatRequest(const char* chat)
//  {
// 	 if (mLoginId < 0)
// 		 return;
//
// 	 ChatBroadcastRequest sendData;
//
// 	 sendData.mPlayerId = mLoginId;
// 	 memcpy(sendData.mChat, chat, strlen(chat));
//
// 	 send((const char*)&sendData, sizeof(ChatBroadcastRequest));
//  }
//
<|endoftext|>


<commit_before>#include <babylon/samples/loaders/gltf/morecomplexmodels/duck_scene.h>

#include <babylon/cameras/arc_rotate_camera.h>
#include <babylon/engines/scene.h>
#include <babylon/helpers/environment_helper.h>
#include <babylon/loading/glTF/gltf_file_loader.h>
#include <babylon/loading/scene_loader.h>

namespace BABYLON {
namespace Samples {

DuckScene::DuckScene(ICanvas* iCanvas) : IRenderableScene(iCanvas)
{
  GLTF2::GLTFFileLoader::RegisterAsSceneLoaderPlugin();
}

DuckScene::~DuckScene()
{
}

const char* DuckScene::getName()
{
  return "Duck Scene (glTF)";
}

void DuckScene::initializeScene(ICanvas* /*canvas*/, Scene* scene)
{
  SceneLoader::ImportMesh(
    {}, "glTF-Sample-Models/2.0/Duck/glTF/", "Duck.gltf", scene,
    [scene](const std::vector<AbstractMeshPtr>& /*meshes*/,
            const std::vector<IParticleSystemPtr>& /*particleSystems*/,
            const std::vector<SkeletonPtr>& /*skeletons*/,
            const std::vector<AnimationGroupPtr>& /*animationGroups*/) {
      scene->createDefaultCameraOrLight(true, true, true);
      // Set the camera position
      auto camera
        = std::static_pointer_cast<ArcRotateCamera>(scene->activeCamera());
      if (camera) {
        camera->setTarget(Vector3(-35.f, 80.f, 0.f));
        camera->alpha  = Math::PI / 1.5f;
        camera->beta   = Math::PI / 3.5f;
        camera->radius = 250.f;
      }
    });
}

} // end of namespace Samples
} // end of namespace BABYLON
<commit_msg>Updated camera settings to show glTF duck scene<commit_after>#include <babylon/samples/loaders/gltf/morecomplexmodels/duck_scene.h>

#include <babylon/cameras/arc_rotate_camera.h>
#include <babylon/engines/scene.h>
#include <babylon/helpers/environment_helper.h>
#include <babylon/loading/glTF/gltf_file_loader.h>
#include <babylon/loading/scene_loader.h>

namespace BABYLON {
namespace Samples {

DuckScene::DuckScene(ICanvas* iCanvas) : IRenderableScene(iCanvas)
{
  GLTF2::GLTFFileLoader::RegisterAsSceneLoaderPlugin();
}

DuckScene::~DuckScene()
{
}

const char* DuckScene::getName()
{
  return "Duck Scene (glTF)";
}

void DuckScene::initializeScene(ICanvas* /*canvas*/, Scene* scene)
{
  SceneLoader::ImportMesh(
    {}, "glTF-Sample-Models/2.0/Duck/glTF/", "Duck.gltf", scene,
    [scene](const std::vector<AbstractMeshPtr>& /*meshes*/,
            const std::vector<IParticleSystemPtr>& /*particleSystems*/,
            const std::vector<SkeletonPtr>& /*skeletons*/,
            const std::vector<AnimationGroupPtr>& /*animationGroups*/) {
      scene->createDefaultCameraOrLight(true, true, true);
      // Set the camera position
      auto camera
        = std::static_pointer_cast<ArcRotateCamera>(scene->activeCamera());
      if (camera) {
        camera->setTarget(Vector3::Zero());
        camera->alpha  = -Math::PI / 2.f;
        camera->beta   = Math::PI / 2.f;
        camera->radius = 6.f;
      }
    });
}

} // end of namespace Samples
} // end of namespace BABYLON
<|endoftext|>