I have finally gotten around to porting the Acan API to T2.
.cpp file:
#include "AcanApi/AcanApi.h"
//const char* ACAN_KEY = "acan_wordsp_2_naplan";
AcanAd::AcanAd()
{
}
AcanAd::~AcanAd()
{
}
void AcanAd::setup(int refreshTime, int maxAttempts, int retryTime, int debug)
{
this->refreshTime = refreshTime;
this->maxAttempts = maxAttempts;
this->retryTime = retryTime;
this->debug = debug;
}
void AcanAd::initialise(int horizontal, int vertical, float scale, int includeWindows, int includeMac)
{
osType = 0;
initialised = 0;
winAds = includeWindows;
macAds = includeMac;
if(initialised == 0)
{
if(scale == 0)
{
scale = 50;
}
createAd(horizontal, vertical, scale);
setAdVisible(1);
}
setDeviceType();
initialised = 1;
}
void AcanAd::setDeviceType()
{
//Char ptr to enable cleanup
char* osRaw = agk::GetDeviceName();
char* osLeft = agk::Left(osRaw, 3);
char* osLower = agk::Lower(osLeft);
std::string os = osLower;
if(os.compare("ios") == 0)
{
osType = 0;
}
else if(os.compare("and") == 0)
{
osType = 1;
}
else
{
osType = 2;
}
//Cleaning up
delete[] osRaw;
delete[] osLeft;
delete[] osLower;
}
void AcanAd::createAd(int horizontal, int vertical, float scale)
{
acan.time = 0;
acan.vis = -1;
acan.hor = 0;
acan.vert = 0;
acan.w = 0;
acan.index = 0;
acan.spriteID = 0;
acan.imageID = 0;
acan.conID = 0;
acan.conState = 0;
acan.response = "";
int fileID = 0;
int displayAd = 0;
std::string imageFile = ""; //Defined inside if statement in T1 version because variables are defined per function
std::string filename = "acan/acan_ad.dat";
if(agk::GetFileExists(filename.data()) == 1)
{
fileID = agk::OpenToRead(filename.data());
char* linePtr = agk::ReadLine(fileID);
std::string line = linePtr;
delete[] linePtr;
char* chrPtr = agk::Chr(31);
if(agk::CountStringTokens(line.data(), chrPtr) == 2)
{
//Getting the string tokens, again char* for cleaning up
char* token1 = agk::GetStringToken(line.data(), chrPtr, 1);
char* token2 = agk::GetStringToken(line.data(), chrPtr, 2);
acan.index = agk::Val(token1);
imageFile = "acan/";
imageFile.append(token2);
delete[] token1;
delete[] token2;
agk::CloseFile(fileID);
if(agk::GetFileExists(imageFile.data()) == 1)
{
displayAd = 1;
}
else
{
agk::DeleteFile(filename.data());
}
}
//Because I don't like that the file can still be open if countTokes does not return 0
/*if(agk::FileIsOpen(fileID))
{
agk::CloseFile(fileID);
}*/
//More cleaning up
delete[] chrPtr;
}
if(displayAd == 1)
{
acan.time = agk::Timer();
acan.imageID = agk::LoadImage(imageFile.data());
acan.spriteID = agk::CreateSprite(acan.imageID);
//agk::FixSpriteToScreen(acan.spriteID, 1);
agk::SetSpriteDepth(acan.spriteID, 899);
setAdVisible(1);
}
setAdPosition(horizontal, vertical, scale);
}
void AcanAd::setAdVisible(int visible)
{
acan.vis = visible;
if(agk::GetSpriteExists(acan.spriteID) == 1)
{
agk::SetSpriteVisible(acan.spriteID, acan.vis);
}
}
void AcanAd::setAdPosition(int horizontal, int vertical, float scale)
{
if(horizontal < 0 && horizontal > 2)
{
errorMessage("Horizontal needs to be between 0 and 2");
return;
}
if(vertical < 0 && vertical > 2)
{
errorMessage("Vertical needs to be between 0 and 2");
return;
}
if(scale < 0 && scale > 100)
{
errorMessage("Scale needs to be between 0 and 100");
return;
}
if(agk::GetVirtualWidth() == 100)
{
acan.w = 100;
}
else
{
acan.w = scale * agk::GetVirtualWidth() / 100;
}
acan.hor = horizontal;
acan.vert = vertical;
if(agk::GetSpriteExists(acan.spriteID) == 1)
{
agk::SetSpriteSize(acan.spriteID, acan.w, -1);
float w = acan.w;
float h = agk::GetSpriteHeight(acan.spriteID);
float x = 0;
if(horizontal == 1)
{
x = 0.5 * (agk::GetVirtualWidth() - w);
}
else if(horizontal == 2)
{
x = agk::GetVirtualWidth() - w;
}
float y = 0;
if(vertical == 1)
{
y = 0.5 * (agk::GetVirtualHeight() - h);
}
else if(vertical == 2)
{
y = agk::GetVirtualHeight() - h;
}
agk::SetSpritePosition(acan.spriteID, x, y);
}
}
void AcanAd::handle()
{
//////////////////////////////////////////
if(initialised == 0)
{
initialise(1, 2, 50, 0, 0);
}
int fileID = 0;
std::string filename = "acan/acan_ad.dat";
float dTime = agk::Timer() - acan.time;
if(acan.conID == 0 && agk::GetInternetState() == 1 && (dTime > refreshTime || acan.time == 0))
{
acan.conID = agk::CreateHTTPConnection();
agk::SetHTTPHost(acan.conID, "www.wordspionagedb.com", 0);
char* indexPtr = agk::Str(acan.index);
char* osPtr = agk::Str(osType);
char* winPtr = agk::Str(winAds);
char* macPtr = agk::Str(macAds);
std::string post = "k=";
post.append(ACAN_KEY);
post.append("&i=");
post.append(indexPtr);
post.append("&os=");
post.append(osPtr);
post.append("&win=");
post.append(winPtr);
post.append("&mac=");
post.append(macPtr);
agk::SendHTTPRequestASync(acan.conID, "agkads/getadinfo.php", post.data());
//Cleaning up
delete[]indexPtr;
delete[]osPtr;
delete[]winPtr;
delete[]macPtr;
acan.conState = 1;
}
if(acan.conID > 0)
{
//ErrorReport::addLine("ConID > 0");
if(acan.conState == 1)
{
//ErrorReport::addLine("conState == 1");
int ready = agk::GetHTTPResponseReady(acan.conID);
if(ready != 0)
{
if(ready == 1)
{
char* separator = agk::Chr(31);
char* responsePtr = agk::GetHTTPResponse(acan.conID);
if(agk::CountStringTokens(responsePtr, separator) == 2)
{
acan.response = responsePtr;
char* localFilePtr = agk::GetStringToken(responsePtr, separator, 2);
std::string localFile = "acan/";
localFile.append(localFilePtr);
int nameLength = agk::Len(localFilePtr);
char* extensionTokenPtr = agk::GetStringToken(localFilePtr, ".", agk::CountStringTokens(localFilePtr, "."));
char* extensionPtr = agk::Lower(extensionTokenPtr);
std::string extension = extensionPtr;
if(nameLength > 20 || extension.compare("png"))
{
errorMessage("Png filename is invalid");
}
else
{
char* encodePtr = agk::HTTPEncode(localFilePtr);
std::string imageFile = "agkads/imgs/";
imageFile.append(encodePtr);
agk::GetHTTPFile(acan.conID, imageFile.data(), localFile.data());
acan.conState = 2;
delete[] encodePtr;
}
//Cleanup time
delete[] localFilePtr;
delete[] extensionTokenPtr;
delete[] extensionPtr;
}
else
{
acan.error++;
acan.conState = 0;
}
//Cleanup
delete[] separator;
delete[] responsePtr;
}
else
{
errorMessage("ready was neighter 1 or 0");
acan.error++;
acan.conState = 0;
acan.time = 0;
}
}
}
else if(acan.conState == 2)
{
int complete = agk::GetHTTPFileComplete(acan.conID);
if(complete == 1)
{
char* separator = agk::Chr(31);
char* newImgPtr = agk::GetStringToken(acan.response.data(), separator, 2);
std::string newImageFile = "acan/";
newImageFile.append(newImgPtr);
if(agk::GetFileExists(newImageFile.data()) == 1)
{
int pass = verifyPNGFile(newImageFile.data(), 50*1024, 480, 50);
if(pass == 0)
{
pass = verifyPNGFile(newImageFile.data(), 50*1024, 480, 80);
}
pass = 1;
if(pass == 1)
{
int fileID = agk::OpenToWrite(filename.data(), 0);
agk::WriteLine(fileID, acan.response.data());
agk::CloseFile(fileID);
int hor = acan.hor;
int vert = acan.vert;
float scale = 100 * acan.w / agk::GetVirtualWidth();
int vis = vis;
if(agk::GetImageExists(acan.imageID) == 1)
{
char* oldImgFilePtr = agk::GetImageFilename(acan.imageID);
if(agk::GetFileExists(oldImgFilePtr) == 1)
{
agk::DeleteFile(oldImgFilePtr);
}
agk::DeleteImage(acan.imageID);
delete[] oldImgFilePtr;
}
char* indexPtr = agk::GetStringToken(acan.response.data(), separator, 1);
int index = agk::Val(indexPtr);
if(agk::GetSpriteExists(acan.spriteID) == 1)
{
acan.imageID = agk::LoadImage(newImageFile.data());
agk::SetSpriteImage(acan.spriteID, acan.imageID);
setAdPosition(hor, vert, scale);
}
else
{
createAd(hor, vert, scale);
}
if(vis != -1)
{
setAdVisible(vis);
}
acan.index = index;
delete[] indexPtr;
}
else
{
agk::DeleteFile(newImageFile.data());
agk::DeleteFile(filename.data());
errorMessage("Image failed PNG verification");
acan.conState = 0;
acan.error++;
acan.time = 0;
}
}
else
{
//ACAN_ErrorMessage("Image failed PNG verification")
errorMessage("Image file does not exist - "); //Modify if you want more info
acan.conState = 0;
acan.error++;
acan.time = 0;
}
acan.conState = 0;
delete[] separator;
delete[] newImgPtr;
}//Conplete check
else if(complete == -1)
{
errorMessage("Failed to download image");
acan.conState = 0;
acan.error++;
acan.time = 0;
}
}
else
{
if(acan.error != 0)
{
acan.time = 0;
if(acan.error >= maxAttempts)
{
acan.doOnce = 0;
acan.error = 0;
acan.time = agk::Timer() + retryTime;
}
}
else
{
acan.time = agk::Timer();
}
agk::CloseHTTPConnection(acan.conID);
agk::DeleteHTTPConnection(acan.conID);
acan.conID = 0;
acan.conState = 0;
acan.response = "";
}
}
//Click handeling
if(agk::GetSpriteExists(acan.spriteID) == 1 && agk::GetPointerPressed() == 1 && acan.index > 0)
{
if(agk::GetSpriteVisible(acan.spriteID) == 1)
{
float ptrX = agk::GetPointerX();
float ptrY = agk::GetPointerY();
if(agk::GetSpriteHitTest(acan.spriteID, ptrX, ptrY) == 1)
{
char* indexPtr = agk::Str(acan.index);
std::string url = "www.wordspionagedb.com/agkads/clickad.php?k=";
url.append(ACAN_KEY);
url.append("&i=");
url.append(indexPtr);
agk::OpenBrowser(url.data());
delete[] indexPtr;
}
}
}
}
void AcanAd::deleteAd()
{
if(agk::GetSpriteExists(acan.spriteID) == 1)
{
agk::DeleteSprite(acan.spriteID);
}
if(agk::GetImageExists(acan.imageID))
{
agk::DeleteImage(acan.imageID);
}
//Clear everything
acan.time = 0;
acan.vis = -1;
acan.hor = 0;
acan.vert = 0;
acan.w = 0;
acan.index = 0;
acan.spriteID = 0;
acan.imageID = 0;
acan.conID = 0;
acan.conState = 0;
acan.response = "";
}
int AcanAd::getAdVisible()
{
int visible = 0;
if(agk::GetSpriteExists(acan.spriteID) == 1)
{
if(agk::GetSpriteVisible(acan.spriteID) == 1)
{
visible = 1;
}
}
return visible;
}
int AcanAd::verifyPNGFile(std::string filename, int maxSize, int w, int h)
{
int pass = 1;
int fileID = agk::OpenToRead(filename.data());
if(agk::GetFileSize(fileID) > maxSize)
{
pass = 0;
}
if(pass == 1)
{
int pngHeader[9] = {0, 137, 80, 78, 71, 13, 10, 26, 10};
for(unsigned int i = 0; i < 8; i++)
{
int b = agk::ReadByte(fileID);
if(b != pngHeader[i+1])
{
pass = 0;
}
}
}
if(pass == 1)
{
int tw = readBigEndian(fileID);
int th = readBigEndian(fileID);
if(tw != w && th != h)
{
pass = 0;
}
}
agk::CloseFile(fileID);
return pass;
}
int AcanAd::readBigEndian(int fileID)
{
int num = -1;
int b1 = agk::ReadByte(fileID);
int b2 = agk::ReadByte(fileID);
int b3 = agk::ReadByte(fileID);
int b4 = agk::ReadByte(fileID);
if(b1 > 126)
{
num = -1;
}
else
{
num = 16777216 * b1 + 65536 * b2 + 256 * b3 + b4;
}
return num;
}
void AcanAd::errorMessage(std::string error)
{
}
.h file
#ifndef H_ACAN
#define H_ACAN
#define ACAN_REFRESH_TIME 10
#define ACAN_MAX_ATTEMPTS 5
#define ACAN_RETRY_TIME 10
#include <string>
#include "agk.h"
const std::string ACAN_KEY = "acan_test";
class AcanAd
{
public:
AcanAd();
~AcanAd();
int refreshTime;
int maxAttempts;
int retryTime;
int debug;
struct ACAN_type
{
float time;
int vis;
int hor;
int vert;
float w;
int index;
int spriteID;
int imageID;
int conID;
int conState;
std::string response;
int error;
int doOnce;
};
ACAN_type acan;
int osType;
int initialised;
int winAds;
int macAds;
void setup(int refreshTime, int maxAttempts, int retryTime, int debug);
void initialise(int horizontal, int vertical, float scale, int includeWindows, int includeMac);
void setDeviceType();
void createAd(int horizontal, int vertical, float scale);
void setAdVisible(int visible);
void setAdPosition(int horizontal, int vertical, float scale);
void handle();
void deleteAd();
int getAdVisible();
int verifyPNGFile(std::string filename, int maxSize, int w, int h);
int readBigEndian(int fileID);
void errorMessage(std::string error);
private:
};
#endif
It works right now but there are some bugs that may need fixing.
1. Only the first ad is displayed, when the next one gets loaded, nothing shows up
2. Something might be causing a crash when using one of the functions (I havn't looked into it and it doesn't happen every time)
3. The image files are not verified, it didn't work propperly so I skipped the verification
I will try to fix those bugs in the future but I need to do something else now so if anyone feels like looking for them, feel free
Also, I don't know if I have made a misstake or if there is something wrong with my code, but I seem to only get ios ads on android, again, it needs more research
To use the API, include AcanApi.h whereever you want and instance the AcanAd class. Call the setup function once, call the instance class to start displaying the ad and the handle function to update it. Apart from the setup function, it works exactly the same as the T1 version except that I have put everything in a class so you could theoreticaly have multiple ads at the same time.
I have only tested it on android in AppGameKit v2 alpha 3.
Say ONE stupid thing and it ends up as a forum signature forever. - Neuro Fuzzy