Click here to Skip to main content
Click here to Skip to main content

C# wrapper for Diablo III API

By , 26 Sep 2012
 

Introduction

This is a simple wrapper for Diablo III published API. I wrote this program in C# 2.0. The winform program will show you any your interested guys information, which include hero level/class/Paragon and items without opening your game.

You can open the solution via VS2012, click the left combobox and select property-Items, add any your favorite guys Diablo III tag, just like iamfqq#1989, this is my tag in the game.

Here is a snapshot for my program.

Background

If you want to check your friends' Diablo III hero, and do not want to open your game, you can use this application to see detailed information.

Blizzard published the API several months ago and I wrote this wrapper for the .NET developer to do some interesting things.

Using the code

Namespace

You should add the using statement at head of your .NET file like below

using GameBaster.Diablo3.API;

How to get profile infomration?

Pass the Diablo III tag string to the constructor of Profile class. The tag format should look like: Yourname#Number.

Profile profile = new Profile(tag);
List<Hero> list = profile.HeroList; 

In current version, the Cache is set to true by default. This means the API will download necessary resources and save .JSON and items pictures to the cache path when you first time run the application. When these resources download, the API will not retrieve them again (in order to improve application performance).

How to display the hero's head picture?

This is a sample code to show a hero's head picture on a button.

using (Stream myStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(hero.HeadPicture))
{ 
        Bitmap bmp = new Bitmap(myStream); 
        btn.BackgroundImage = bmp; 
        btn.BackgroundImageLayout = ImageLayout.None; 
}

If you go to definition of HeadPicture you'll find similar code. The head picture resources are located at the folder HeadPicture, they had been merged into the windows form application resources.

public string HeadPicture
{
   get{
      return String.Format("Diablo3Profile.HeadPicture.{0}_{1}.png", this._class.Replace("-", ""), this.male);
      }
}

What's the class Profile?

Class Profile is the entry for this API which include 3 main properties: MonstersKilled,ElitesKilled and a dictionary that contains all of the heros who belong to the tag.

The D3 API doc told us, we could get user profile information via a HTTP GET operation. You could find this line in the constructor of the class Profile. Be careful, do NOT forget the last "/" after the {0} parameter.

this.apiurl = String.Format("http://us.battle.net/api/d3/profile/{0}/", tag.Replace("#", "-"));  

When you download the data through the WebClient class, you could use JSON helper or any other helper class to analyze the data. Because I do not know much about JSON, I had to use String.IndexOf and String.SubString methods to finish the resolving work.

In fact, in the Profile constructor method, I'd resolved the JSON string and split basic hero information, such as ID, Name, Level, Class, Paragon Class, etc.

What's the class Hero?

Class Hero include the basic hero information just like the last line of "What's the class Profile", and also a dictionary which contains all of the items which belong to this hero.

You could get the hero's items through the D3 API via a HTTP GET. The URL is a little different with the prior profile URL. It looks like this: 

string url = String.Format("http://us.battle.net/api/d3/profile/{0}/hero/{1}", this.tag.Replace("#", "-"), this.id); 

You may find the D3 API require the tag string should use the "-" instead of the "#" .And the {1} parameter is the hero id, you can retrieve this from the class Profile.

All of the items information are retrieved from public method GetItemList.

public Dictionary<string, Item> GetItemList() 

This method does not need any parameters, and will return a generic Dictionary instance which include all of the items. The key in the dictionary is the item type instead of a individual name, such as "head" instead of "Some Head Item". And the value in the dictionary is an instance of the class Item.

Here are parts of the method GetItemList. All of the main work is done by another method, "GetItem".

<pre>itemlist.Add("head", GetItem(info, "head"));
itemlist.Add("torso", GetItem(info, "torso"));
itemlist.Add("feet", GetItem(info, "feet"));
itemlist.Add("hands", GetItem(info, "hands"));
itemlist.Add("shoulders", GetItem(info, "shoulders"));
itemlist.Add("legs", GetItem(info, "legs"));
itemlist.Add("bracers", GetItem(info, "bracers"));
itemlist.Add("mainhand", GetItem(info, "mainHand"));
itemlist.Add("offhand", GetItem(info, "offHand"));
itemlist.Add("waist", GetItem(info, "waist"));
itemlist.Add("rightfinger", GetItem(info, "rightFinger"));
itemlist.Add("leftfinger", GetItem(info, "leftFinger"));
itemlist.Add("neck", GetItem(info, "neck"));    

In the GetItem method, I simply resolve the JSON string by the parameter key.

private Item GetItem(string content, string key)

Here, we should use the other D3 API via HTTP GET operation.

string url = "http://us.battle.net/api/d3/data/" + itemtip;   

The itemtip is split from the JSON data. When you send the GET request to http://us.battle.net, you'll get the detailed information for this item. The information is big and rich, you can find a number of things, such as Name, Type, Image, Color. You can also find some basic but importand properties, like strength, vitality, intelligence, MF and resistance all.

At last, I add the GDI+ information in the API code. I do not have a clear thoughts on where to put such image loaction, lable location and line location information. Maybe I'll refactor the code and move these complex Points array to other class.

I think, now you could understand the key part of this application.

What's the class Profile?

Class Helper include some configuration info, such as Cache, JSON analysis. Again, I do not have the knowledge on how to resolve the JSON string, So I use the simple String operations to complete this task.

How to merge all of information and show a magic picture?

All of the UI operations are coded in the file MyPanel.cs. The class MyPanel is derived from UserControl, for a better performance, I'd set the style on this control just like below code. The 3 ControlStyles are merged by the "OR" operator, this can greatly improve the GDI+ performance.

private void MyPanel_Load(object sender, EventArgs e)
{
	this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
        this.UpdateStyles();
}

The kernel code are all in the method MyPanel_Paint, which include 7 parts

  • Create a buffered DC: Created the other DC object from an empty image.
  • Draw background image: Draw the background image in the DC. Until now, the D3 contains 10 background images, you can find this from folder Background.
  • Draw hero name and level and class : Simply using the Graphics.DrawString method, the font I use is Palatino Linotype, font size is 48.0F.
  • Draw all of the items: The Items include item picture, line and descriptions. The most important part is these GDI+ objects location information. I stored all of these into the Item instance, you can find it from class Hero, method GetItem.
  • Draw 3 check boxes: The 3 check boxes are the main property for hero, MF and Resistance all. For different hero class, the 1st check box will show the difference property name, such as Strength, Intelligences.
  • Draw tool tip: The tooltip is the detailed decriptions for an item. I extract the basic and hidden data from the JSON attributes_raw section in the methodGetAttributesRaw.
  • Draw buffered image to current DC: When all of the things drawn completed in the second DC, now you can quickly copy the image data to current DC.

Points of Interest

You can find the original Blizzard API here:https://github.com/Blizzard/d3-api-docs

History

This is a version 0.1. The next version will include hero skill information, and will add event handler to some methods.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Charles Ju
Software Developer
China China
Member
I love C#.
I love using windbg to help customers solve the performance issues.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Question是否支持台湾(tw)服务器,以及中文角色名显示? [modified]memberAnsonHsu2 Oct '12 - 20:17 
是否支持台湾(tw)服务器,以及中文角色名显示?
我试了一下,手动修改地址为http://tw.battle获取不了json数据。
另外,如果游戏角色为中文显示都是乱码,不知道是不支持还是我语言设置的问题。
 
这个API找了好久,相当棒!鼎力支持~
 
附我的tag:string tag = "Anson#3913/index?locale=zh_TW";

modified 3 Oct '12 - 3:13.

AnswerRe: 是否支持台湾(tw)服务器,以及中文角色名显示?memberCharles Ju3 Oct '12 - 2:54 
Sorry, I'd tried all of the Encoding from Encoding.GetEncodings, it failed. And also failed when try the {0:X2} format to convert Chinese character name to byte info.
GeneralRe: 是否支持台湾(tw)服务器,以及中文角色名显示?memberAnsonHsu3 Oct '12 - 3:16 
ok. Thanks a lot! Smile | :)
GeneralRe: 是否支持台湾(tw)服务器,以及中文角色名显示?memberAnsonHsu6 Oct '12 - 5:22 
我试了一下,以下方法可以成功获得没有乱码的中文
        
private static string DownloadData(string url)
        {
 
            try
            {
                var webRes = ((HttpWebRequest)WebRequest.Create(url)).GetResponse();
                var streamReader = new StreamReader(webRes.GetResponseStream());
                string responce = streamReader.ReadToEnd();
                webRes.Close();
                if (responce == "{\n\"code\" : \"OOPS\",\n\"reason\" : \"There was a problem processing the request.\"\n}")
                    return "error";
                else
                    return responce;
            }
            catch
            {
                return "";
            }
        }

GeneralMy vote of 5memberrspercy6529 Sep '12 - 12:09 
Nice Job
BugSome issuesmemberCharles Ju26 Sep '12 - 20:38 
1. I do not test the GDI+ result on different screen resolution. My laptop's resolution is 1400*900.
2. You must manully create the folder c:\temp\diabloe3profilecache to avoid exception thrown from API.cs, line 128,
using (FileStream writter = new FileStream(fullpath, FileMode.Create))

GeneralRe: Some issuesmemberrspercy6526 Sep '12 - 22:00 
That is not the problem I am Having. I added code to add the folder if it did not exist.
The problem was in the myPanel.cs Control
 
Public Property Hero() As Hero
        Get
            Return Me._hero
        End Get
 
        Set(value As Hero)
            Me._hero = value
            Me.itemlist = _hero.GetItemList()
        End Set
    End Property
 
Me.itemlist = _hero.GetItemList was throwing the exception. I corrected that.
 
A new problem has arisen. In the Refresh(tag As String) sub in the mainform is where I have found a new problem...
 
Dim myStream As Stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(hero.HeadPicture)
Dim bmp As New Bitmap(myStream)
 
The program runs, when I click on your tag in the list box, myStream is throwing a Null exception, but, there is a bitmap in the hero.HeadPicture call. It is not being passed to (myStream). I really like this app as I have alot of friends playing Diablo III and I would like to get it working.
 
I converted it to VB 10 and this is the only problem I have thus far.
Thanx for your time once more.
rspercy65

QuestionGood ArticlememberAl-Samman Mahmoud26 Sep '12 - 12:42 
Good Article I hope to C more Smile | :)
BugException Is being thrown... [modified]memberrspercy6526 Sep '12 - 7:01 
In MyPanel.cs... In the Property Hero...
this.itemlist = hero.GetItemList();
 public Hero Hero
        {
            get { return this.hero; }
            set
            {
                this.hero = value;
                this.itemlist = hero.GetItemList();
            }
        }
 
This is where I get this Exception...
"Check to determine if the Object is Null before calling the method"
 
Your app builds OK...But when I execute it, It does not work so good.
rspercy65


modified 26 Sep '12 - 13:49.

GeneralRe: Exception Is being thrown...memberCharles Ju26 Sep '12 - 20:35 
Please check Mainform.designer.cs file, try to search "this.panelInfo.Hero", if the line is not commentted, please comment this line and run again.
 
If the line already comment, please show me the detailed callstack information when exception thrown.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130516.1 | Last Updated 26 Sep 2012
Article Copyright 2012 by Charles Ju
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid