Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

merge master #50

Merged
merged 4 commits into from May 8, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
24,845 changes: 0 additions & 24,845 deletions data/cards.json

This file was deleted.

1 change: 1 addition & 0 deletions dist/win/setup.iss
Expand Up @@ -47,6 +47,7 @@ Source: "../../../../Qt/Qt5.5.1/5.5/msvc2013/bin/Qt5Widgets.dll"; DestDir: "{app
Source: "../../../../Qt/Qt5.5.1/5.5/msvc2013/bin/Qt5WinExtras.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "../../../../Qt/Qt5.5.1/5.5/msvc2013/bin/Qt5Gui.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "../../../../Qt/Qt5.5.1/5.5/msvc2013/bin/Qt5Network.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "../../../../Qt/Qt5.5.1/5.5/msvc2013/bin/Qt5Xml.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "../../../../Qt/Qt5.5.1/5.5/msvc2013/plugins/imageformats/*.dll"; Excludes: "*d.dll"; DestDir: "{app}/imageformats"; Flags: ignoreversion
Source: "../../../../Qt/Qt5.5.1/5.5/msvc2013/plugins/platforms/*.dll"; Excludes: "*d.dll"; DestDir: "{app}/platforms"; Flags: ignoreversion

Expand Down
1 change: 0 additions & 1 deletion resources.qrc
Expand Up @@ -23,6 +23,5 @@
<file>icons/win.ico</file>
<file>icons/logo.png</file>
<file>data/rank_classifier.json</file>
<file>data/cards.json</file>
</qresource>
</RCC>
151 changes: 151 additions & 0 deletions src/HearthstoneCardDB.cpp
@@ -0,0 +1,151 @@
#include "HearthstoneCardDB.h"
#include "Settings.h"
#include "Hearthstone.h"

#include <QtXml>

QString ExtractCardDefsXmlFromUnity3d( QString fileName, QString desiredLocale ) {
QFile file( fileName );

if( !file.open( QIODevice::ReadOnly ) ) {
DBG( "Couldn't open %s", qt2cstr( fileName ) );
return "";
}

QString xml;

QByteArray data = file.readAll();
for( int idx = data.indexOf( "<CardDefs>" ); idx != -1; idx = data.indexOf( "<CardDefs>", idx + 1 ) ) {
// Determine size
int size;
memcpy( &size, data.constData() + ( idx - 4 ), 4 );

// Determine locale
int localeOffset = idx - 5;
while( localeOffset > 0 && data[ localeOffset - 1 ] != char(0) )
localeOffset--;

int localeSizeOffset = localeOffset - 4;
if( localeOffset < 0 && localeSizeOffset < 0 ) {
DBG( "Offsets < 0. Skip" );
continue;
}

int localeSize;
memcpy( &localeSize, data.constData() + localeSizeOffset, 4 );
QString locale = QString::fromUtf8( data.constData() + localeOffset, localeSize );

if( locale == desiredLocale ) {
DBG( "Found desired locale %s (card defs size %d)", qt2cstr( desiredLocale ), size );
xml = QString::fromUtf8( data.constData() + idx, size );
break;
}
}

return xml;
}

HearthstoneCardDB::HearthstoneCardDB( QObject *parent )
: QObject( parent )
{
}

int HearthstoneCardDB::Count() const {
return mCards.count();
}

bool HearthstoneCardDB::Contains( const QString& id ) const {
return mCards.contains( id );
}

int HearthstoneCardDB::Mana( const QString& id ) const {
return mCards[ id ][ "cost" ].toInt();
}

QString HearthstoneCardDB::Name( const QString& id ) const {
return mCards[ id ][ "name" ].toString();
}

QString HearthstoneCardDB::Type( const QString& id ) const {
int value = mCards[ id ][ "type" ].toInt();
switch( value ) {
case 3:
case 4:
return "minion";
break;

case 5:
case 6:
return "ability";

case 7:
return "weapon";

case 10:
return "hero";

default:
return "unknown";
}
}

bool HearthstoneCardDB::Load() {
Unload();

DBG( "Load Card DB" );

QString locale = Locale();
QString platform = "Win";
#ifdef Q_OS_MAC
platform = "OSX";
#endif

QString path = QString( "%1/Data/%2/cardxml0.unity3d" ).arg( Settings::Instance()->HearthstoneDirectoryPath() ).arg( platform );
QString xmlData = ExtractCardDefsXmlFromUnity3d( path, locale );

if( !xmlData.isEmpty() ) {
QXmlSimpleReader reader;
CardCollector cardCollector;
reader.setContentHandler( &cardCollector );

connect( &cardCollector, &CardCollector::CardCollected, this, [&]( const QString& id, const QVariantMap& card ) {
mCards[ id ] = card;
});

QXmlInputSource input;
input.setData( xmlData );
reader.parse( &input );

DBG( "Loaded %d cards", mCards.count() );
}

return true;
}

bool HearthstoneCardDB::Unload() {
DBG( "Unload Card DB" );
mCards.clear();
return true;
}

bool HearthstoneCardDB::Loaded() const {
return !mCards.empty();
}

QString HearthstoneCardDB::Locale() const {
QString locale = "enUS";

QString path = QString( "%1/Launcher.db" ).arg( Settings::Instance()->HearthstoneDirectoryPath() );
QFile file( path );

if( file.open( QIODevice::ReadOnly ) ) {
QTextStream stream( &file );
locale = stream.readLine();
} else {
DBG( "Couldn't open %s to determine locale", qt2cstr( path ) );
}

DBG( "Locale = %s", qt2cstr( locale )) ;
return locale;
}

114 changes: 114 additions & 0 deletions src/HearthstoneCardDB.h
@@ -0,0 +1,114 @@
#pragma once

#include <QMap>
#include <QString>
#include <QVariant>

#include <QtXml>

class HearthstoneCardDB : public QObject
{
Q_OBJECT

private:
QMap< QString, QVariantMap > mCards;

private:
QString Locale() const;

public:
HearthstoneCardDB( QObject *parent = 0 );

bool Load();
bool Unload();

bool Loaded() const;

int Count() const;
bool Contains( const QString& id ) const;

int Mana( const QString& id ) const;
QString Name( const QString& id ) const;
QString Type( const QString& id ) const;
};

class CardCollector : public QObject, public QXmlDefaultHandler
{
Q_OBJECT

private:
QString mNextAttributeName;
QString mCurrentCardId;
QVariantMap mCurrentAttributes;

public:
CardCollector()
: QXmlDefaultHandler(), mNextAttributeName()
{
}

~CardCollector() {
}

bool startElement( const QString&,
const QString&,
const QString& qName,
const QXmlAttributes& attribs )
{
static const QMap< int, QString > ATTRIBUTES_BY_TAG_ID = {
{ 185, "name" },
{ 48, "cost" },
{ 202, "type" }
};

if( qName == "Entity" ) {
mCurrentCardId = attribs.value( "CardID" );
} else if( qName == "Tag" ) {

int enumId = attribs.value( "enumID" ).toInt();
if( ATTRIBUTES_BY_TAG_ID.contains( enumId ) ) {
const QString& attributeName = ATTRIBUTES_BY_TAG_ID[ enumId ];

mNextAttributeName = "";
QString value = attribs.value( "value" );
if( value.isEmpty() ) {
// read <tag>value</tag>
mNextAttributeName = attributeName;
} else {
// read <tag value="1"></tag>
mCurrentAttributes[ attributeName ] = value;
}
}

}

return true;
}

bool characters( const QString& ch ) {
if( !mNextAttributeName.isEmpty() ) {
mCurrentAttributes[ mNextAttributeName ] = ch;
mNextAttributeName = "";
}
return true;
}

bool endElement( const QString&,
const QString&,
const QString& qName )
{
if( qName == "Entity" && !mCurrentCardId.isEmpty() ) {
emit CardCollected( mCurrentCardId, mCurrentAttributes );

mCurrentCardId = "";
mCurrentAttributes.clear();
}

return true;
}

signals:
void CardCollected( const QString& id, const QVariantMap& card );

};

36 changes: 12 additions & 24 deletions src/ui/Overlay.cpp
Expand Up @@ -179,8 +179,6 @@ Overlay::Overlay( QWidget *parent )

connect( Settings::Instance(), &Settings::OverlayEnabledChanged, this, &Overlay::HandleOverlaySettingChanged );

LoadCards();

hide();

#ifdef Q_OS_MAC
Expand Down Expand Up @@ -218,24 +216,6 @@ void Overlay::CheckForHover() {
}
}

void Overlay::LoadCards() {
QFile file( ":/data/cards.json" );
bool opened = file.open( QIODevice::ReadOnly | QIODevice::Text );
assert( opened );

QByteArray jsonData = file.readAll();
QJsonParseError error;
QJsonArray jsonCards = QJsonDocument::fromJson( jsonData, &error ).array();
assert( error.error == QJsonParseError::NoError );

mCardDB.clear();

for( QJsonValueRef jsonCardRef : jsonCards ) {
QJsonObject jsonCard = jsonCardRef.toObject();
mCardDB[ jsonCard["id"].toString() ] = jsonCard.toVariantMap();
}
}

void PaintHistoryInScreen( QPainter& painter, const OverlayHistoryWindow& wnd, const QPoint& pos ) {
int padding = 10;

Expand Down Expand Up @@ -300,8 +280,16 @@ void Overlay::Update() {
#ifdef Q_OS_WIN
setAttribute( Qt::WA_QuitOnClose ); // otherwise taskkill /IM Track-o-Bot.exe does not work (http://www.qtcentre.org/threads/11713-Qt-Tool?p=62466#post62466)
#endif

if( !mCardDB.Loaded() ) {
mCardDB.Load();
}
} else {
hide();

if( mCardDB.Loaded() ) {
mCardDB.Unload();
}
}

update();
Expand All @@ -327,12 +315,12 @@ void Overlay::UpdateHistoryFor( Player player, const ::CardHistoryList& list ) {
continue;
}

if( !mCardDB.contains( cardId ) ) {
if( !mCardDB.Contains( cardId ) ) {
DBG( "Card %s not found", qt2cstr( cardId ) );
continue;
}

if( mCardDB[ cardId ][ "type" ] == "hero" ) {
if( mCardDB.Type( cardId ) == "hero" ) {
continue;
}

Expand All @@ -342,8 +330,8 @@ void Overlay::UpdateHistoryFor( Player player, const ::CardHistoryList& list ) {

QVariantMap& entry = entries[ cardId ];
entry[ "count" ] = entry.value( "count", 0 ).toInt() + 1;
entry[ "mana" ] = mCardDB[ cardId ][ "mana" ];
entry[ "name" ] = mCardDB[ cardId ][ "name" ];
entry[ "mana" ] = mCardDB.Mana( cardId );
entry[ "name" ] = mCardDB.Name( cardId );
}

OverlayHistoryList* ref;
Expand Down
6 changes: 4 additions & 2 deletions src/ui/Overlay.h
Expand Up @@ -11,6 +11,8 @@ namespace Ui { class Overlay; }

#include "../Result.h"

#include "../HearthstoneCardDB.h"

typedef QList< QVariantMap > OverlayHistoryList;

class Overlay : public QMainWindow
Expand All @@ -23,15 +25,15 @@ class Overlay : public QMainWindow
OverlayHistoryList mPlayerHistory;
OverlayHistoryList mOpponentHistory;

QMap< QString, QVariantMap > mCardDB;

Player mShowPlayerHistory;

QRect mPlayerDeckRect;
QRect mOpponentDeckRect;

QTimer mCheckForHoverTimer;

HearthstoneCardDB mCardDB;

void LoadCards();
void UpdateHistoryFor( Player player, const ::CardHistoryList& list );
void Update();
Expand Down