<commit_before>#include "NTClient.h"
using namespace std;

NTClient::NTClient(int interval, double _accuracy) {
	typeIntervalMS = interval;
	accuracy = _accuracy;
	hasError = false;
	firstConnect = true;
	connected = false;
	lessonLen = 0;
	lidx = 0;
	log = new NTLogger("(Not logged in)");
}
NTClient::~NTClient() {
	delete log;
	if (wsh != nullptr) {
		delete wsh;
		wsh = nullptr;
	}
}
bool NTClient::login(string username, string password) {
	log->type(LOG_HTTP);
	log->wr("Logging into the NitroType account...\n");
	log->setUsername(username);
	uname = username;
	pword = password;
	bool ret = true;
	string data = string("username=");
	data += uname;
	data += "&password=";
	data += pword;
	data += "&adb=1&tz=America%2FChicago"; // No need to have anything other than Chicago timezone
	httplib::SSLClient loginReq(NITROTYPE_HOSTNAME, HTTPS_PORT);
	shared_ptr<httplib::Response> res = loginReq.post(NT_LOGIN_ENDPOINT, data, "application/x-www-form-urlencoded; charset=UTF-8");
	if (res) {
		bool foundLoginCookie = false;
		for (int i = 0; i < res->cookies.size(); ++i) {
			string cookie = res->cookies.at(i);
			addCookie(Utils::extractCKey(cookie), Utils::extractCValue(cookie));
			if (cookie.find("ntuserrem=") == 0) {
				foundLoginCookie = true;
				token = Utils::extractCValue(cookie);
				log->type(LOG_HTTP);
				log->wr("Resolved ntuserrem login token.\n");
				// addCookie("ntuserrem", token);
			}
		}
		if (!foundLoginCookie) {
			ret = false;
			cout << "Unable to locate the login cookie. Maybe try a different account?\n";
		}
	} else {
		ret = false;
		cout << "Login request failed. This might be a network issue. Maybe try resetting your internet connection?\n";
	}
	bool success = getPrimusSID();
	if (!success) return false;
	return ret;
}
bool NTClient::connect() {
	wsh = new Hub();
	time_t tnow = time(0);
	rawCookieStr = Utils::stringifyCookies(&cookies);
	stringstream uristream;
	uristream  << "wss://realtime1.nitrotype.com:443/realtime/?_primuscb=" << tnow << "-0&EIO=3&transport=websocket&sid=" << primusSid << "&t=" << tnow << "&b64=1";
	string wsURI = uristream.str();
	log->type(LOG_CONN);
	log->wr("Attempting to open a WebSocket on NitroType realtime server...\n");
	if (firstConnect) {
		addListeners();
	}
	// cout << "Cookies: " << rawCookieStr << endl << endl;
	// Create override headers
	SMap customHeaders;
	customHeaders["Cookie"] = rawCookieStr;
	customHeaders["Origin"] = "https://www.nitrotype.com";
	customHeaders["User-Agent"] = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/55.0.2883.87 Chrome/55.0.2883.87 Safari/537.36";
	// customHeaders["Host"] = "realtime1.nitrotype.com";
	wsh->connect(wsURI, (void*)this, customHeaders, 7000);
	// wsh->connect(wsURI);
	if (firstConnect) {
		wsh->run();
		firstConnect = false;
	}
	return true;
}
void NTClient::addCookie(string key, string val) {
	SPair sp = SPair(key, val);
	cookies.push_back(sp);
}
bool NTClient::getPrimusSID() {
	time_t tnow = time(0);
	log->type(LOG_HTTP);
	log->wr("Resolving Primus SID...\n");
	rawCookieStr = Utils::stringifyCookies(&cookies);
	stringstream squery;
	squery << "?_primuscb=" << tnow << "-0&EIO=3&transport=polling&t=" << tnow << "-0&b64=1";
	string queryStr = squery.str();

	httplib::SSLClient loginReq(NT_REALTIME_HOST, HTTPS_PORT);
	string path = NT_PRIMUS_ENDPOINT + queryStr;
	shared_ptr<httplib::Response> res = loginReq.get(path.c_str(), rawCookieStr.c_str());
	if (res) {
		json jres = json::parse(res->body.substr(4, res->body.length()));
		primusSid = jres["sid"];
		log->type(LOG_HTTP);
		log->wr("Resolved Primus SID successfully.\n");
		// addCookie("io", primusSid);
	} else {
		cout << "Error retrieving primus handshake data.\n";
		return false;
	}
	return true;
}
string NTClient::getJoinPacket(int avgSpeed) {
	stringstream ss;
	ss << "4{\"stream\":\"race\",\"msg\":\"join\",\"payload\":{\"debugging\":false,\"avgSpeed\":"
	<< avgSpeed
	<< ",\"forceEarlyPlace\":true,\"track\":\"desert\",\"music\":\"city_nights\"}}";
	return ss.str();
}
void NTClient::addListeners() {
	assert(wsh != nullptr);
	wsh->onError([this](void* udata) {
		cout << "Failed to connect to WebSocket server." << endl;
		hasError = true;
	});
	wsh->onConnection([this](WebSocket<CLIENT>* wsocket, HttpRequest req) {
		log->type(LOG_CONN);
		log->wr("Established a WebSocket connection with the realtime server.\n");
		onConnection(wsocket, req);
	});
	wsh->onDisconnection([this](WebSocket<CLIENT>* wsocket, int code, char* msg, size_t len) {
		log->type(LOG_CONN);
		log->wr("Disconnected from the realtime server.\n");
		onDisconnection(wsocket, code, msg, len);
	});
	wsh->onMessage([this](WebSocket<CLIENT>* ws, char* msg, size_t len, OpCode opCode) {
		onMessage(ws, msg, len, opCode);
	});
}
void NTClient::onDisconnection(WebSocket<CLIENT>* wsocket, int code, char* msg, size_t len) {
	cout << "Disconn message: " << string(msg, len) << endl;
	cout << "Disconn code: " << code << endl;
}
void NTClient::handleData(WebSocket<CLIENT>* ws, json* j) {
	// Uncomment to dump all raw JSON packets
	// cout << "Recieved json data:" << endl << j->dump(4) << endl;
	if (j->operator[]("msg") == "setup") {
		log->type(LOG_RACE);
		log->wr("I joined a new race.\n");
	} else if (j->operator[]("msg") == "joined") {
		string joinedName = j->operator[]("payload")["profile"]["username"];
		string dispName;
		try {
			dispName = j->operator[]("payload")["profile"]["displayName"];
		} catch (const exception& e) {
			dispName = "[None]";
		}
		log->type(LOG_RACE);
		if (joinedName == "bot") {
			log->wr("Bot user '");
			log->wrs(dispName);
			log->wrs("' joined the race.\n");
		} else {
			log->wr("Human user '");
			log->wrs(joinedName);
			log->wrs("' joined the race.\n");
		}
	} else if (j->operator[]("msg") == "status" && j->operator[]("payload")["status"] == "countdown") {
		log->type(LOG_RACE);
		log->wr("The race has started.\n");
		lesson = j->operator[]("payload")["l"];
		lessonLen = lesson.length();
		lidx = 0;
		this_thread::sleep_for(chrono::milliseconds(50));
		type(ws);
	}
}
void NTClient::onMessage(WebSocket<CLIENT>* ws, char* msg, size_t len, OpCode opCode) {
	if (opCode != OpCode::TEXT) {
		cout << "The realtime server did not send a text packet for some reason, ignoring.\n";
		return;
	}
	string smsg = string(msg, len);
	if (smsg == "3probe") {
		// Response to initial connection probe
		ws->send("5", OpCode::TEXT);
		// Join packet
		this_thread::sleep_for(chrono::seconds(1));
		string joinTo = getJoinPacket(20); // 20 WPM just to test
		ws->send(joinTo.c_str(), OpCode::TEXT);
	} else if (smsg.length() > 2 && smsg[0] == '4' && smsg[1] == '{') {
		string rawJData = smsg.substr(1, smsg.length());
		json jdata;
		try {
			jdata = json::parse(rawJData);
		} catch (const exception& e) {
			// Some error parsing real race data, something must be wrong
			cout << "There was an issue parsing server data: " << e.what() << endl;
			return;
		}
		handleData(ws, &jdata);
	} else {
		cout << "Recieved unknown WebSocket message: '" << smsg << "'\n";
	}
}
void NTClient::onConnection(WebSocket<CLIENT>* wsocket, HttpRequest req) {
	// Send a probe, which is required for connection
	wsocket->send("2probe", OpCode::TEXT);
}
void NTClient::sendTypePacket(WebSocket<CLIENT>* ws, int idx, bool isRight) {
	json p = {
		{"stream", "race"},
		{"msg", "update"},
		{"payload", {}}
	};
	if (isRight) {
		p["payload"]["t"] = idx;
	} else {
		p["payload"]["e"] = idx;
	}
	string packet = "4" + p.dump();
	ws->send(packet.c_str(), OpCode::TEXT);
}
void NTClient::type(WebSocket<CLIENT>* ws) {
	if (lidx > lessonLen) {
		// All characters have been typed
		return;
	}
	int low = typeIntervalMS - 10;
	int high = typeIntervalMS + 10;
	bool isRight = Utils::randBool(accuracy);
	int sleepFor = Utils::randInt(low, high);
	if (low < 10) {
		low = 10;
	}
	cout << "Typing with index: " << lidx << ", isRight: " << isRight << ", sleepFor: " << sleepFor << endl;
	sendTypePacket(ws, lidx, isRight);
	lidx++;
	this_thread::sleep_for(chrono::milliseconds(sleepFor));
	type(ws); // Call the function until the lesson has been "typed"
}<commit_msg>Log lesson length<commit_after>#include "NTClient.h"
using namespace std;

NTClient::NTClient(int interval, double _accuracy) {
	typeIntervalMS = interval;
	accuracy = _accuracy;
	hasError = false;
	firstConnect = true;
	connected = false;
	lessonLen = 0;
	lidx = 0;
	log = new NTLogger("(Not logged in)");
}
NTClient::~NTClient() {
	delete log;
	if (wsh != nullptr) {
		delete wsh;
		wsh = nullptr;
	}
}
bool NTClient::login(string username, string password) {
	log->type(LOG_HTTP);
	log->wr("Logging into the NitroType account...\n");
	log->setUsername(username);
	uname = username;
	pword = password;
	bool ret = true;
	string data = string("username=");
	data += uname;
	data += "&password=";
	data += pword;
	data += "&adb=1&tz=America%2FChicago"; // No need to have anything other than Chicago timezone
	httplib::SSLClient loginReq(NITROTYPE_HOSTNAME, HTTPS_PORT);
	shared_ptr<httplib::Response> res = loginReq.post(NT_LOGIN_ENDPOINT, data, "application/x-www-form-urlencoded; charset=UTF-8");
	if (res) {
		bool foundLoginCookie = false;
		for (int i = 0; i < res->cookies.size(); ++i) {
			string cookie = res->cookies.at(i);
			addCookie(Utils::extractCKey(cookie), Utils::extractCValue(cookie));
			if (cookie.find("ntuserrem=") == 0) {
				foundLoginCookie = true;
				token = Utils::extractCValue(cookie);
				log->type(LOG_HTTP);
				log->wr("Resolved ntuserrem login token.\n");
				// addCookie("ntuserrem", token);
			}
		}
		if (!foundLoginCookie) {
			ret = false;
			cout << "Unable to locate the login cookie. Maybe try a different account?\n";
		}
	} else {
		ret = false;
		cout << "Login request failed. This might be a network issue. Maybe try resetting your internet connection?\n";
	}
	bool success = getPrimusSID();
	if (!success) return false;
	return ret;
}
bool NTClient::connect() {
	wsh = new Hub();
	time_t tnow = time(0);
	rawCookieStr = Utils::stringifyCookies(&cookies);
	stringstream uristream;
	uristream  << "wss://realtime1.nitrotype.com:443/realtime/?_primuscb=" << tnow << "-0&EIO=3&transport=websocket&sid=" << primusSid << "&t=" << tnow << "&b64=1";
	string wsURI = uristream.str();
	log->type(LOG_CONN);
	log->wr("Attempting to open a WebSocket on NitroType realtime server...\n");
	if (firstConnect) {
		addListeners();
	}
	// cout << "Cookies: " << rawCookieStr << endl << endl;
	// Create override headers
	SMap customHeaders;
	customHeaders["Cookie"] = rawCookieStr;
	customHeaders["Origin"] = "https://www.nitrotype.com";
	customHeaders["User-Agent"] = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/55.0.2883.87 Chrome/55.0.2883.87 Safari/537.36";
	// customHeaders["Host"] = "realtime1.nitrotype.com";
	wsh->connect(wsURI, (void*)this, customHeaders, 7000);
	// wsh->connect(wsURI);
	if (firstConnect) {
		wsh->run();
		firstConnect = false;
	}
	return true;
}
void NTClient::addCookie(string key, string val) {
	SPair sp = SPair(key, val);
	cookies.push_back(sp);
}
bool NTClient::getPrimusSID() {
	time_t tnow = time(0);
	log->type(LOG_HTTP);
	log->wr("Resolving Primus SID...\n");
	rawCookieStr = Utils::stringifyCookies(&cookies);
	stringstream squery;
	squery << "?_primuscb=" << tnow << "-0&EIO=3&transport=polling&t=" << tnow << "-0&b64=1";
	string queryStr = squery.str();

	httplib::SSLClient loginReq(NT_REALTIME_HOST, HTTPS_PORT);
	string path = NT_PRIMUS_ENDPOINT + queryStr;
	shared_ptr<httplib::Response> res = loginReq.get(path.c_str(), rawCookieStr.c_str());
	if (res) {
		json jres = json::parse(res->body.substr(4, res->body.length()));
		primusSid = jres["sid"];
		log->type(LOG_HTTP);
		log->wr("Resolved Primus SID successfully.\n");
		// addCookie("io", primusSid);
	} else {
		cout << "Error retrieving primus handshake data.\n";
		return false;
	}
	return true;
}
string NTClient::getJoinPacket(int avgSpeed) {
	stringstream ss;
	ss << "4{\"stream\":\"race\",\"msg\":\"join\",\"payload\":{\"debugging\":false,\"avgSpeed\":"
	<< avgSpeed
	<< ",\"forceEarlyPlace\":true,\"track\":\"desert\",\"music\":\"city_nights\"}}";
	return ss.str();
}
void NTClient::addListeners() {
	assert(wsh != nullptr);
	wsh->onError([this](void* udata) {
		cout << "Failed to connect to WebSocket server." << endl;
		hasError = true;
	});
	wsh->onConnection([this](WebSocket<CLIENT>* wsocket, HttpRequest req) {
		log->type(LOG_CONN);
		log->wr("Established a WebSocket connection with the realtime server.\n");
		onConnection(wsocket, req);
	});
	wsh->onDisconnection([this](WebSocket<CLIENT>* wsocket, int code, char* msg, size_t len) {
		log->type(LOG_CONN);
		log->wr("Disconnected from the realtime server.\n");
		onDisconnection(wsocket, code, msg, len);
	});
	wsh->onMessage([this](WebSocket<CLIENT>* ws, char* msg, size_t len, OpCode opCode) {
		onMessage(ws, msg, len, opCode);
	});
}
void NTClient::onDisconnection(WebSocket<CLIENT>* wsocket, int code, char* msg, size_t len) {
	cout << "Disconn message: " << string(msg, len) << endl;
	cout << "Disconn code: " << code << endl;
}
void NTClient::handleData(WebSocket<CLIENT>* ws, json* j) {
	// Uncomment to dump all raw JSON packets
	// cout << "Recieved json data:" << endl << j->dump(4) << endl;
	if (j->operator[]("msg") == "setup") {
		log->type(LOG_RACE);
		log->wr("I joined a new race.\n");
	} else if (j->operator[]("msg") == "joined") {
		string joinedName = j->operator[]("payload")["profile"]["username"];
		string dispName;
		try {
			dispName = j->operator[]("payload")["profile"]["displayName"];
		} catch (const exception& e) {
			dispName = "[None]";
		}
		log->type(LOG_RACE);
		if (joinedName == "bot") {
			log->wr("Bot user '");
			log->wrs(dispName);
			log->wrs("' joined the race.\n");
		} else {
			log->wr("Human user '");
			log->wrs(joinedName);
			log->wrs("' joined the race.\n");
		}
	} else if (j->operator[]("msg") == "status" && j->operator[]("payload")["status"] == "countdown") {
		log->type(LOG_RACE);
		log->wr("The race has started.\n");
		lesson = j->operator[]("payload")["l"];
		lessonLen = lesson.length();
		lidx = 0;
		log->wr("Lesson length:");
		log->operator<<(lessonLen);
		log->ln();
		this_thread::sleep_for(chrono::milliseconds(50));
		type(ws);
	}
}
void NTClient::onMessage(WebSocket<CLIENT>* ws, char* msg, size_t len, OpCode opCode) {
	if (opCode != OpCode::TEXT) {
		cout << "The realtime server did not send a text packet for some reason, ignoring.\n";
		return;
	}
	string smsg = string(msg, len);
	if (smsg == "3probe") {
		// Response to initial connection probe
		ws->send("5", OpCode::TEXT);
		// Join packet
		this_thread::sleep_for(chrono::seconds(1));
		string joinTo = getJoinPacket(20); // 20 WPM just to test
		ws->send(joinTo.c_str(), OpCode::TEXT);
	} else if (smsg.length() > 2 && smsg[0] == '4' && smsg[1] == '{') {
		string rawJData = smsg.substr(1, smsg.length());
		json jdata;
		try {
			jdata = json::parse(rawJData);
		} catch (const exception& e) {
			// Some error parsing real race data, something must be wrong
			cout << "There was an issue parsing server data: " << e.what() << endl;
			return;
		}
		handleData(ws, &jdata);
	} else {
		cout << "Recieved unknown WebSocket message: '" << smsg << "'\n";
	}
}
void NTClient::onConnection(WebSocket<CLIENT>* wsocket, HttpRequest req) {
	// Send a probe, which is required for connection
	wsocket->send("2probe", OpCode::TEXT);
}
void NTClient::sendTypePacket(WebSocket<CLIENT>* ws, int idx, bool isRight) {
	json p = {
		{"stream", "race"},
		{"msg", "update"},
		{"payload", {}}
	};
	if (isRight) {
		p["payload"]["t"] = idx;
	} else {
		p["payload"]["e"] = idx;
	}
	string packet = "4" + p.dump();
	ws->send(packet.c_str(), OpCode::TEXT);
}
void NTClient::type(WebSocket<CLIENT>* ws) {
	if (lidx > lessonLen) {
		// All characters have been typed
		return;
	}
	int low = typeIntervalMS - 10;
	int high = typeIntervalMS + 10;
	bool isRight = Utils::randBool(accuracy);
	int sleepFor = Utils::randInt(low, high);
	if (low < 10) {
		low = 10;
	}
	cout << "Typing with index: " << lidx << ", isRight: " << isRight << ", sleepFor: " << sleepFor << endl;
	sendTypePacket(ws, lidx, isRight);
	lidx++;
	this_thread::sleep_for(chrono::milliseconds(sleepFor));
	type(ws); // Call the function until the lesson has been "typed"
}<|endoftext|>


<commit_before>#include "NTClient.h"
using namespace std;

NTClient::NTClient(int interval, double _accuracy) {
	typeIntervalMS = interval;
	accuracy = _accuracy;
	hasError = false;
	firstConnect = true;
	connected = false;
	lessonLen = 0;
	lidx = 0;
	log = new NTLogger("(Not logged in)");
}
NTClient::~NTClient() {
	delete log;
	if (wsh != nullptr) {
		delete wsh;
		wsh = nullptr;
	}
}
bool NTClient::login(string username, string password) {
	log->type(LOG_HTTP);
	log->wr("Logging into the NitroType account...\n");
	log->setUsername(username);
	uname = username;
	pword = password;
	bool ret = true;
	string data = string("username=");
	data += uname;
	data += "&password=";
	data += pword;
	data += "&adb=1&tz=America%2FChicago"; // No need to have anything other than Chicago timezone
	httplib::SSLClient loginReq(NITROTYPE_HOSTNAME, HTTPS_PORT);
	shared_ptr<httplib::Response> res = loginReq.post(NT_LOGIN_ENDPOINT, data, "application/x-www-form-urlencoded; charset=UTF-8");
	if (res) {
		bool foundLoginCookie = false;
		for (int i = 0; i < res->cookies.size(); ++i) {
			string cookie = res->cookies.at(i);
			addCookie(Utils::extractCKey(cookie), Utils::extractCValue(cookie));
			if (cookie.find("ntuserrem=") == 0) {
				foundLoginCookie = true;
				token = Utils::extractCValue(cookie);
				log->type(LOG_HTTP);
				log->wr("Resolved ntuserrem login token.\n");
				// addCookie("ntuserrem", token);
			}
		}
		if (!foundLoginCookie) {
			ret = false;
			cout << "Unable to locate the login cookie. Maybe try a different account?\n";
		}
	} else {
		ret = false;
		cout << "Login request failed. This might be a network issue. Maybe try resetting your internet connection?\n";
	}
	bool success = getPrimusSID();
	if (!success) return false;
	return ret;
}
bool NTClient::connect() {
	wsh = new Hub();
	time_t tnow = time(0);
	rawCookieStr = Utils::stringifyCookies(&cookies);
	stringstream uristream;
	uristream  << "wss://realtime1.nitrotype.com:443/realtime/?_primuscb=" << tnow << "-0&EIO=3&transport=websocket&sid=" << primusSid << "&t=" << tnow << "&b64=1";
	string wsURI = uristream.str();
	log->type(LOG_CONN);
	log->wr("Attempting to open a WebSocket on NitroType realtime server...\n");
	if (firstConnect) {
		addListeners();
	}
	// cout << "Cookies: " << rawCookieStr << endl << endl;
	// Create override headers
	SMap customHeaders;
	customHeaders["Cookie"] = rawCookieStr;
	customHeaders["Origin"] = "https://www.nitrotype.com";
	customHeaders["User-Agent"] = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/55.0.2883.87 Chrome/55.0.2883.87 Safari/537.36";
	// customHeaders["Host"] = "realtime1.nitrotype.com";
	wsh->connect(wsURI, (void*)this, customHeaders, 7000);
	// wsh->connect(wsURI);
	if (firstConnect) {
		wsh->run();
		firstConnect = false;
	}
	return true;
}
void NTClient::addCookie(string key, string val) {
	SPair sp = SPair(key, val);
	cookies.push_back(sp);
}
bool NTClient::getPrimusSID() {
	time_t tnow = time(0);
	log->type(LOG_HTTP);
	log->wr("Resolving Primus SID...\n");
	rawCookieStr = Utils::stringifyCookies(&cookies);
	stringstream squery;
	squery << "?_primuscb=" << tnow << "-0&EIO=3&transport=polling&t=" << tnow << "-0&b64=1";
	string queryStr = squery.str();

	httplib::SSLClient loginReq(NT_REALTIME_HOST, HTTPS_PORT);
	string path = NT_PRIMUS_ENDPOINT + queryStr;
	shared_ptr<httplib::Response> res = loginReq.get(path.c_str(), rawCookieStr.c_str());
	if (res) {
		json jres = json::parse(res->body.substr(4, res->body.length()));
		primusSid = jres["sid"];
		log->type(LOG_HTTP);
		log->wr("Resolved Primus SID successfully.\n");
		// addCookie("io", primusSid);
	} else {
		cout << "Error retrieving primus handshake data.\n";
		return false;
	}
	return true;
}
string NTClient::getJoinPacket(int avgSpeed) {
	stringstream ss;
	ss << "4{\"stream\":\"race\",\"msg\":\"join\",\"payload\":{\"debugging\":false,\"avgSpeed\":"
	<< avgSpeed
	<< ",\"forceEarlyPlace\":true,\"track\":\"desert\",\"music\":\"city_nights\"}}";
	return ss.str();
}
void NTClient::addListeners() {
	assert(wsh != nullptr);
	wsh->onError([this](void* udata) {
		cout << "Failed to connect to WebSocket server." << endl;
		hasError = true;
	});
	wsh->onConnection([this](WebSocket<CLIENT>* wsocket, HttpRequest req) {
		log->type(LOG_CONN);
		log->wr("Established a WebSocket connection with the realtime server.\n");
		onConnection(wsocket, req);
	});
	wsh->onDisconnection([this](WebSocket<CLIENT>* wsocket, int code, char* msg, size_t len) {
		log->type(LOG_CONN);
		log->wr("Disconnected from the realtime server.\n");
		onDisconnection(wsocket, code, msg, len);
	});
	wsh->onMessage([this](WebSocket<CLIENT>* ws, char* msg, size_t len, OpCode opCode) {
		onMessage(ws, msg, len, opCode);
	});
}
void NTClient::onDisconnection(WebSocket<CLIENT>* wsocket, int code, char* msg, size_t len) {
	cout << "Disconn message: " << string(msg, len) << endl;
	cout << "Disconn code: " << code << endl;
}
void NTClient::handleData(WebSocket<CLIENT>* ws, json* j) {
	// Uncomment to dump all raw JSON packets
	// cout << "Recieved json data:" << endl << j->dump(4) << endl;
	if (j->operator[]("msg") == "setup") {
		log->type(LOG_RACE);
		log->wr("I joined a new race.\n");
	} else if (j->operator[]("msg") == "joined") {
		string joinedName = j->operator[]("payload")["profile"]["username"];
		string dispName;
		try {
			dispName = j->operator[]("payload")["profile"]["displayName"];
		} catch (const exception& e) {
			dispName = "[None]";
		}
		log->type(LOG_RACE);
		if (joinedName == "bot") {
			log->wr("Bot user '");
			log->wrs(dispName);
			log->wrs("' joined the race.\n");
		} else {
			log->wr("Human user '");
			log->wrs(joinedName);
			log->wrs("' joined the race.\n");
		}
	} else if (j->operator[]("msg") == "status" && j->operator[]("payload")["status"] == "countdown") {
		log->type(LOG_RACE);
		log->wr("The race has started.\n");
		lesson = j->operator[]("payload")["l"];
		lessonLen = lesson.length();
		lidx = 0;
		type();
	}
}
void NTClient::onMessage(WebSocket<CLIENT>* ws, char* msg, size_t len, OpCode opCode) {
	if (opCode != OpCode::TEXT) {
		cout << "The realtime server did not send a text packet for some reason, ignoring.\n";
		return;
	}
	string smsg = string(msg, len);
	if (smsg == "3probe") {
		// Response to initial connection probe
		ws->send("5", OpCode::TEXT);
		// Join packet
		this_thread::sleep_for(chrono::seconds(1));
		string joinTo = getJoinPacket(20); // 20 WPM just to test
		ws->send(joinTo.c_str(), OpCode::TEXT);
	} else if (smsg.length() > 2 && smsg[0] == '4' && smsg[1] == '{') {
		string rawJData = smsg.substr(1, smsg.length());
		json jdata;
		try {
			jdata = json::parse(rawJData);
		} catch (const exception& e) {
			// Some error parsing real race data, something must be wrong
			cout << "There was an issue parsing server data: " << e.what() << endl;
			return;
		}
		handleData(ws, &jdata);
	} else {
		cout << "Recieved unknown WebSocket message: '" << smsg << "'\n";
	}
}
void NTClient::onConnection(WebSocket<CLIENT>* wsocket, HttpRequest req) {
	// Send a probe, which is required for connection
	wsocket->send("2probe", OpCode::TEXT);
}
void NTClient::sendTypePacket(WebSocket<CLIENT>* ws, int idx, bool isRight) {
	json p = {
		{"stream", "race"},
		{"msg", "update"},
		{"payload", {}}
	};
	if (isRight) {
		p["payload"]["t"] = idx;
	} else {
		p["payload"]["e"] = idx;
	}
	string packet = "4" + p.dump();
	ws->send(packet.c_str(), OpCode::TEXT);
}
void NTClient::type() {
	// TODO : add typing function
	int low = typeIntervalMS - 10;
	int high = typeIntervalMS + 10;
	bool isRight = Utils::randBool(accuracy);
	if (low < 10) {
		low = 10;
	}
}<commit_msg>Wait a bit before starting the typing algorithm<commit_after>#include "NTClient.h"
using namespace std;

NTClient::NTClient(int interval, double _accuracy) {
	typeIntervalMS = interval;
	accuracy = _accuracy;
	hasError = false;
	firstConnect = true;
	connected = false;
	lessonLen = 0;
	lidx = 0;
	log = new NTLogger("(Not logged in)");
}
NTClient::~NTClient() {
	delete log;
	if (wsh != nullptr) {
		delete wsh;
		wsh = nullptr;
	}
}
bool NTClient::login(string username, string password) {
	log->type(LOG_HTTP);
	log->wr("Logging into the NitroType account...\n");
	log->setUsername(username);
	uname = username;
	pword = password;
	bool ret = true;
	string data = string("username=");
	data += uname;
	data += "&password=";
	data += pword;
	data += "&adb=1&tz=America%2FChicago"; // No need to have anything other than Chicago timezone
	httplib::SSLClient loginReq(NITROTYPE_HOSTNAME, HTTPS_PORT);
	shared_ptr<httplib::Response> res = loginReq.post(NT_LOGIN_ENDPOINT, data, "application/x-www-form-urlencoded; charset=UTF-8");
	if (res) {
		bool foundLoginCookie = false;
		for (int i = 0; i < res->cookies.size(); ++i) {
			string cookie = res->cookies.at(i);
			addCookie(Utils::extractCKey(cookie), Utils::extractCValue(cookie));
			if (cookie.find("ntuserrem=") == 0) {
				foundLoginCookie = true;
				token = Utils::extractCValue(cookie);
				log->type(LOG_HTTP);
				log->wr("Resolved ntuserrem login token.\n");
				// addCookie("ntuserrem", token);
			}
		}
		if (!foundLoginCookie) {
			ret = false;
			cout << "Unable to locate the login cookie. Maybe try a different account?\n";
		}
	} else {
		ret = false;
		cout << "Login request failed. This might be a network issue. Maybe try resetting your internet connection?\n";
	}
	bool success = getPrimusSID();
	if (!success) return false;
	return ret;
}
bool NTClient::connect() {
	wsh = new Hub();
	time_t tnow = time(0);
	rawCookieStr = Utils::stringifyCookies(&cookies);
	stringstream uristream;
	uristream  << "wss://realtime1.nitrotype.com:443/realtime/?_primuscb=" << tnow << "-0&EIO=3&transport=websocket&sid=" << primusSid << "&t=" << tnow << "&b64=1";
	string wsURI = uristream.str();
	log->type(LOG_CONN);
	log->wr("Attempting to open a WebSocket on NitroType realtime server...\n");
	if (firstConnect) {
		addListeners();
	}
	// cout << "Cookies: " << rawCookieStr << endl << endl;
	// Create override headers
	SMap customHeaders;
	customHeaders["Cookie"] = rawCookieStr;
	customHeaders["Origin"] = "https://www.nitrotype.com";
	customHeaders["User-Agent"] = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/55.0.2883.87 Chrome/55.0.2883.87 Safari/537.36";
	// customHeaders["Host"] = "realtime1.nitrotype.com";
	wsh->connect(wsURI, (void*)this, customHeaders, 7000);
	// wsh->connect(wsURI);
	if (firstConnect) {
		wsh->run();
		firstConnect = false;
	}
	return true;
}
void NTClient::addCookie(string key, string val) {
	SPair sp = SPair(key, val);
	cookies.push_back(sp);
}
bool NTClient::getPrimusSID() {
	time_t tnow = time(0);
	log->type(LOG_HTTP);
	log->wr("Resolving Primus SID...\n");
	rawCookieStr = Utils::stringifyCookies(&cookies);
	stringstream squery;
	squery << "?_primuscb=" << tnow << "-0&EIO=3&transport=polling&t=" << tnow << "-0&b64=1";
	string queryStr = squery.str();

	httplib::SSLClient loginReq(NT_REALTIME_HOST, HTTPS_PORT);
	string path = NT_PRIMUS_ENDPOINT + queryStr;
	shared_ptr<httplib::Response> res = loginReq.get(path.c_str(), rawCookieStr.c_str());
	if (res) {
		json jres = json::parse(res->body.substr(4, res->body.length()));
		primusSid = jres["sid"];
		log->type(LOG_HTTP);
		log->wr("Resolved Primus SID successfully.\n");
		// addCookie("io", primusSid);
	} else {
		cout << "Error retrieving primus handshake data.\n";
		return false;
	}
	return true;
}
string NTClient::getJoinPacket(int avgSpeed) {
	stringstream ss;
	ss << "4{\"stream\":\"race\",\"msg\":\"join\",\"payload\":{\"debugging\":false,\"avgSpeed\":"
	<< avgSpeed
	<< ",\"forceEarlyPlace\":true,\"track\":\"desert\",\"music\":\"city_nights\"}}";
	return ss.str();
}
void NTClient::addListeners() {
	assert(wsh != nullptr);
	wsh->onError([this](void* udata) {
		cout << "Failed to connect to WebSocket server." << endl;
		hasError = true;
	});
	wsh->onConnection([this](WebSocket<CLIENT>* wsocket, HttpRequest req) {
		log->type(LOG_CONN);
		log->wr("Established a WebSocket connection with the realtime server.\n");
		onConnection(wsocket, req);
	});
	wsh->onDisconnection([this](WebSocket<CLIENT>* wsocket, int code, char* msg, size_t len) {
		log->type(LOG_CONN);
		log->wr("Disconnected from the realtime server.\n");
		onDisconnection(wsocket, code, msg, len);
	});
	wsh->onMessage([this](WebSocket<CLIENT>* ws, char* msg, size_t len, OpCode opCode) {
		onMessage(ws, msg, len, opCode);
	});
}
void NTClient::onDisconnection(WebSocket<CLIENT>* wsocket, int code, char* msg, size_t len) {
	cout << "Disconn message: " << string(msg, len) << endl;
	cout << "Disconn code: " << code << endl;
}
void NTClient::handleData(WebSocket<CLIENT>* ws, json* j) {
	// Uncomment to dump all raw JSON packets
	// cout << "Recieved json data:" << endl << j->dump(4) << endl;
	if (j->operator[]("msg") == "setup") {
		log->type(LOG_RACE);
		log->wr("I joined a new race.\n");
	} else if (j->operator[]("msg") == "joined") {
		string joinedName = j->operator[]("payload")["profile"]["username"];
		string dispName;
		try {
			dispName = j->operator[]("payload")["profile"]["displayName"];
		} catch (const exception& e) {
			dispName = "[None]";
		}
		log->type(LOG_RACE);
		if (joinedName == "bot") {
			log->wr("Bot user '");
			log->wrs(dispName);
			log->wrs("' joined the race.\n");
		} else {
			log->wr("Human user '");
			log->wrs(joinedName);
			log->wrs("' joined the race.\n");
		}
	} else if (j->operator[]("msg") == "status" && j->operator[]("payload")["status"] == "countdown") {
		log->type(LOG_RACE);
		log->wr("The race has started.\n");
		lesson = j->operator[]("payload")["l"];
		lessonLen = lesson.length();
		lidx = 0;
		this_thread::sleep_for(chrono::milliseconds(50));
		type();
	}
}
void NTClient::onMessage(WebSocket<CLIENT>* ws, char* msg, size_t len, OpCode opCode) {
	if (opCode != OpCode::TEXT) {
		cout << "The realtime server did not send a text packet for some reason, ignoring.\n";
		return;
	}
	string smsg = string(msg, len);
	if (smsg == "3probe") {
		// Response to initial connection probe
		ws->send("5", OpCode::TEXT);
		// Join packet
		this_thread::sleep_for(chrono::seconds(1));
		string joinTo = getJoinPacket(20); // 20 WPM just to test
		ws->send(joinTo.c_str(), OpCode::TEXT);
	} else if (smsg.length() > 2 && smsg[0] == '4' && smsg[1] == '{') {
		string rawJData = smsg.substr(1, smsg.length());
		json jdata;
		try {
			jdata = json::parse(rawJData);
		} catch (const exception& e) {
			// Some error parsing real race data, something must be wrong
			cout << "There was an issue parsing server data: " << e.what() << endl;
			return;
		}
		handleData(ws, &jdata);
	} else {
		cout << "Recieved unknown WebSocket message: '" << smsg << "'\n";
	}
}
void NTClient::onConnection(WebSocket<CLIENT>* wsocket, HttpRequest req) {
	// Send a probe, which is required for connection
	wsocket->send("2probe", OpCode::TEXT);
}
void NTClient::sendTypePacket(WebSocket<CLIENT>* ws, int idx, bool isRight) {
	json p = {
		{"stream", "race"},
		{"msg", "update"},
		{"payload", {}}
	};
	if (isRight) {
		p["payload"]["t"] = idx;
	} else {
		p["payload"]["e"] = idx;
	}
	string packet = "4" + p.dump();
	ws->send(packet.c_str(), OpCode::TEXT);
}
void NTClient::type() {
	// TODO : add typing function
	int low = typeIntervalMS - 10;
	int high = typeIntervalMS + 10;
	bool isRight = Utils::randBool(accuracy);
	if (low < 10) {
		low = 10;
	}
}<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011-2014.
// Distributed under the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <string>
#include <iostream>
#include <vector>
#include <atomic>

#include <boost/program_options/options_description.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/variables_map.hpp>

#include "Options.hpp"

#include "cxxopts.hpp"

using namespace eddic;

namespace po = boost::program_options;

namespace {

std::pair<std::string, std::string> numeric_parser(const std::string& s){
    if (s.find("-32") == 0) {
        return make_pair("32", std::string("true"));
    } else if (s.find("-64") == 0) {
        return make_pair("64", std::string("true"));
    } else {
        return make_pair(std::string(), std::string());
    }
}

std::atomic<bool> description_flag;

po::options_description visible("Usage : eddic [options] source.eddi");
po::options_description all("Usage : eddic [options] source.eddi");

std::unordered_map<std::string, std::vector<std::string>> triggers;

cxxopts::Options options("eddic", "  source.eddi");

void add_trigger(const std::string& option, const std::vector<std::string>& childs){
   triggers[option] = childs;
}

void init_descriptions(){
    po::options_description general("General options");
    general.add_options()
        ("help,h", "Generate this help message")
        ("assembly,S", "Generate only the assembly")
        ("keep,k", "Keep the assembly file")
        ("version", "Print the version of eddic")
        ("output,o", po::value<std::string>()->default_value("a.out"), "Set the name of the executable")

        ("debug,g", "Add debugging symbols")

        ("template-depth", po::value<std::string>()->default_value("100"), "Define the maximum template depth")

        ("32", "Force the compilation for 32 bits platform")
        ("64", "Force the compilation for 64 bits platform")

        ("warning-all", "Enable all the warning messages")
        ("warning-unused", "Warn about unused variables, parameters and functions")
        ("warning-cast", "Warn about useless casts")
        ("warning-effects", "Warn about statements without effect")
        ("warning-includes", "Warn about useless includes")
        ;

    po::options_description display("Display options");
    display.add_options()
        ("ast", "Print the Abstract Syntax Tree representation of the source")
        ("ast-raw", "Print the Abstract Syntax Tree representation of the source coming directly from the parser before any pass is run on the AST. ")
        ("ast-only", "Only print the Abstract Syntax Tree representation of the source (do not continue compilation after printing)")

        ("mtac", "Print the medium-level Three Address Code representation of the source")
        ("mtac-opt", "Print the medium-level Three Address Code representation of the source before any optimization has been performed")
        ("mtac-only", "Only print the medium-level Three Address Code representation of the source (do not continue compilation after printing)")

        ("ltac-pre", "Print the low-level Three Address Code representation of the source before allocation of registers")
        ("ltac-alloc", "Print the low-level Three Address Code representation of the source before optimization")
        ("ltac", "Print the final low-level Three Address Code representation of the source")
        ("ltac-only", "Only print the low-level Three Address Code representation of the source (do not continue compilation after printing)")
        ;

    po::options_description optimization("Optimization options");
    optimization.add_options()
        ("Opt,O", po::value<std::string>()->implicit_value("0")->default_value("2"), "Define the optimization level")
        ("O0", "Disable all optimizations")
        ("O1", "Enable low-level optimizations")
        ("O2", "Enable all optimizations improving the speed but do imply a space tradeoff.")
        ("O3", "Enable all optimizations improving the speed but can increase the size of the program.")

        ("fglobal-optimization", "Enable optimizer engine")
        ("fparameter-allocation", "Enable parameter allocation in register")
        ("fpeephole-optimization", "Enable peephole optimizer")
        ("fomit-frame-pointer", "Omit frame pointer from functions")
        ("finline-functions", "Enable inlining")
        ("fno-inline-functions", "Disable inlining")
        ("funroll-loops", "Enable Loop Unrolling")
        ("fcomplete-peel-loops", "Enable Complete Loop Peeling")
        ;

    po::options_description backend("Backend options");
    backend.add_options()
        ("log", po::value<std::string>()->default_value("0"), "Define the logging")
        ("quiet,q", "Do not print anything")
        ("verbose,v", "Make the compiler verbose")
        ("single-threaded", "Disable the multi-threaded optimization")
        ("time", "Activate the timing system")
        ("stats", "Activate the statistics system")
        ("input", po::value<std::string>(), "Input file")
        ;

    all.add(general).add(display).add(optimization).add(backend);
    visible.add(general).add(display).add(optimization);

    options.add_options("General")
        ("h,help", "Generate this help message")
        ("S,assembly", "Generate only the assembly")
        ("k,keep", "Keep the assembly file")
        ("version", "Print the version of eddic")
        ("o,output", "Set the name of the executable", cxxopts::value<std::string>()->default_value("a.out"))
        ("g,debug", "Add debugging symbols")
        ("template-depth", "Define the maximum template depth", cxxopts::value<std::string>()->default_value("100"))
        ("32", "Force the compilation for 32 bits platform")
        ("64", "Force the compilation for 64 bits platform")
        ("warning-all", "Enable all the warning messages")
        ("warning-unused", "Warn about unused variables, parameters and functions")
        ("warning-cast", "Warn about useless casts")
        ("warning-effects", "Warn about statements without effect")
        ("warning-includes", "Warn about useless includes")
        ;

    options.add_options("Display")
        ("ast", "Print the Abstract Syntax Tree representation of the source")
        ("ast-raw", "Print the Abstract Syntax Tree representation of the source coming directly from the parser before any pass is run on the AST. ")
        ("ast-only", "Only print the Abstract Syntax Tree representation of the source (do not continue compilation after printing)")
        ("mtac", "Print the medium-level Three Address Code representation of the source")
        ("mtac-opt", "Print the medium-level Three Address Code representation of the source before any optimization has been performed")
        ("mtac-only", "Only print the medium-level Three Address Code representation of the source (do not continue compilation after printing)")
        ("ltac-pre", "Print the low-level Three Address Code representation of the source before allocation of registers")
        ("ltac-alloc", "Print the low-level Three Address Code representation of the source before optimization")
        ("ltac", "Print the final low-level Three Address Code representation of the source")
        ("ltac-only", "Only print the low-level Three Address Code representation of the source (do not continue compilation after printing)")
        ;

    options.add_options("Optimization")
        ("O,Opt", "Define the optimization level", cxxopts::value<std::string>()->implicit_value("0")->default_value("2"))
        ("O0", "Disable all optimizations")
        ("O1", "Enable low-level optimizations")
        ("O2", "Enable all optimizations improving the speed but do imply a space tradeoff.")
        ("O3", "Enable all optimizations improving the speed but can increase the size of the program.")
        ("fglobal-optimization", "Enable optimizer engine")
        ("fparameter-allocation", "Enable parameter allocation in register")
        ("fpeephole-optimization", "Enable peephole optimizer")
        ("fomit-frame-pointer", "Omit frame pointer from functions")
        ("finline-functions", "Enable inlining")
        ("fno-inline-functions", "Disable inlining")
        ("funroll-loops", "Enable Loop Unrolling")
        ("fcomplete-peel-loops", "Enable Complete Loop Peeling")
        ;

    options.add_options("Backend")
        ("log", "Define the logging", cxxopts::value<std::string>()->default_value("0"))
        ("q,quiet", "Do not print anything")
        ("v,verbose", "Make the compiler verbose")
        ("single-threaded", "Disable the multi-threaded optimization")
        ("time", "Activate the timing system")
        ("stats", "Activate the statistics system")
        ("input", "Input file", cxxopts::value<std::string>())
        ;

    add_trigger("warning-all", {"warning-unused", "warning-cast", "warning-effects", "warning-includes"});

    //Special triggers for optimization levels
    add_trigger("__1", {"fpeephole-optimization"});
    add_trigger("__2", {"fglobal-optimization", "fomit-frame-pointer", "fparameter-allocation", "finline-functions"});
    add_trigger("__3", {"funroll-loops", "fcomplete-peel-loops", "funswitch-loops"});
}

inline void trigger_childs(std::shared_ptr<Configuration> configuration, const std::vector<std::string>& childs){
    for(auto& child : childs){
        configuration->values[child].defined = true;
        configuration->values[child].value = std::string("true");
    }
}

} //end of anonymous namespace

std::shared_ptr<Configuration> eddic::parseOptions(int argc, const char* argv[]) {
    //Create a new configuration
    auto configuration = std::make_shared<Configuration>();

    try {
        //Only if the description has not been already defined
        if(!description_flag.load()){
            bool old_value = description_flag.load();
            if(description_flag.compare_exchange_strong(old_value, true)){
                init_descriptions();
            }
        }

        //Add the option of the input file
        po::positional_options_description p;
        p.add("input", -1);

        //Create a new set of options
        po::variables_map options;

        //Parse the command line options
        po::store(po::command_line_parser(argc, argv).options(all).extra_parser(numeric_parser).positional(p).run(), options);
        po::notify(options);

        //Transfer the options in the eddic configuration
        for(auto& option : all.options()){
            ConfigValue value;

            if(options.count(option->long_name())){
                value.defined = true;
                value.value = options[option->long_name()].as<std::string>();
            } else {
                value.defined = false;
                value.value = std::string("false");
            }

            configuration->values[option->long_name()] = value;
        }

        if(options.count("O0") + options.count("O1") + options.count("O2") > 1){
            std::cout << "Invalid command line options : only one optimization level should be set" << std::endl;

            return nullptr;
        }

        if(options.count("64") && options.count("32")){
            std::cout << "Invalid command line options : a compilation cannot be both 32 and 64 bits" << std::endl;

            return nullptr;
        }

        //Update optimization level based on special switches
        if(options.count("O0")){
            configuration->values["Opt"].value = "0";
        } else if(options.count("O1")){
            configuration->values["Opt"].value = "1";
        } else if(options.count("O2")){
            configuration->values["Opt"].value = "2";
        } else if(options.count("O3")){
            configuration->values["Opt"].value = "3";
        }

        //Triggers dependent options
        for(auto& trigger : triggers){
            if(configuration->option_defined(trigger.first)){
                trigger_childs(configuration, trigger.second);
            }
        }

        if(configuration->option_int_value("Opt") >= 1){
            trigger_childs(configuration, triggers["__1"]);
        }

        if(configuration->option_int_value("Opt") >= 2){
            trigger_childs(configuration, triggers["__2"]);
        }

        if(configuration->option_int_value("Opt") >= 3){
            trigger_childs(configuration, triggers["__3"]);
        }
    } catch (const po::ambiguous_option& e) {
        std::cout << "Invalid command line options: " << e.what() << std::endl;

        return nullptr;
    } catch (const po::unknown_option& e) {
        std::cout << "Invalid command line options: " << e.what() << std::endl;

        return nullptr;
    } catch (const po::multiple_occurrences& e) {
        std::cout << "Invalid command line options: Multiple occurrences of " << e.get_option_name() << std::endl;

        return nullptr;
    }

    return configuration;
}

bool Configuration::option_defined(const std::string& option_name){
    return values[option_name].defined;
}

std::string Configuration::option_value(const std::string& option_name){
    return values[option_name].value;
}

int Configuration::option_int_value(const std::string& option_name){
    return boost::lexical_cast<int>(values[option_name].value);
}

void eddic::print_help(){
    std::cout << visible << std::endl;

    std::cout << options.help({"General", "Display", "Optimization"}) << std::endl;
}

void eddic::print_version(){
    std::cout << "eddic version 1.2.3" << std::endl;
}
<commit_msg>Complete use of cxxopts<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011-2014.
// Distributed under the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <string>
#include <iostream>
#include <vector>
#include <atomic>

#include <boost/program_options/options_description.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/variables_map.hpp>

#include "Options.hpp"

#include "cxxopts.hpp"

using namespace eddic;

namespace po = boost::program_options;

namespace {

std::pair<std::string, std::string> numeric_parser(const std::string& s){
    if (s.find("-32") == 0) {
        return make_pair("32", std::string("true"));
    } else if (s.find("-64") == 0) {
        return make_pair("64", std::string("true"));
    } else {
        return make_pair(std::string(), std::string());
    }
}

std::atomic<bool> description_flag;

po::options_description visible("Usage : eddic [options] source.eddi");
po::options_description all("Usage : eddic [options] source.eddi");

std::unordered_map<std::string, std::vector<std::string>> triggers;

void add_trigger(const std::string& option, const std::vector<std::string>& childs){
   triggers[option] = childs;
}

void init_options(cxxopts::Options& options){
    options.add_options("General")
        ("h,help", "Generate this help message")
        ("S,assembly", "Generate only the assembly")
        ("k,keep", "Keep the assembly file")
        ("version", "Print the version of eddic")
        ("o,output", "Set the name of the executable", cxxopts::value<std::string>()->default_value("a.out"))
        ("g,debug", "Add debugging symbols")
        ("template-depth", "Define the maximum template depth", cxxopts::value<std::string>()->default_value("100"))
        ("32", "Force the compilation for 32 bits platform")
        ("64", "Force the compilation for 64 bits platform")
        ("warning-all", "Enable all the warning messages")
        ("warning-unused", "Warn about unused variables, parameters and functions")
        ("warning-cast", "Warn about useless casts")
        ("warning-effects", "Warn about statements without effect")
        ("warning-includes", "Warn about useless includes")
        ;

    options.add_options("Display")
        ("ast", "Print the Abstract Syntax Tree representation of the source")
        ("ast-raw", "Print the Abstract Syntax Tree representation of the source coming directly from the parser before any pass is run on the AST. ")
        ("ast-only", "Only print the Abstract Syntax Tree representation of the source (do not continue compilation after printing)")
        ("mtac", "Print the medium-level Three Address Code representation of the source")
        ("mtac-opt", "Print the medium-level Three Address Code representation of the source before any optimization has been performed")
        ("mtac-only", "Only print the medium-level Three Address Code representation of the source (do not continue compilation after printing)")
        ("ltac-pre", "Print the low-level Three Address Code representation of the source before allocation of registers")
        ("ltac-alloc", "Print the low-level Three Address Code representation of the source before optimization")
        ("ltac", "Print the final low-level Three Address Code representation of the source")
        ("ltac-only", "Only print the low-level Three Address Code representation of the source (do not continue compilation after printing)")
        ;

    options.add_options("Optimization")
        ("O,Opt", "Define the optimization level", cxxopts::value<std::string>()->implicit_value("0")->default_value("2"))
        ("O0", "Disable all optimizations")
        ("O1", "Enable low-level optimizations")
        ("O2", "Enable all optimizations improving the speed but do imply a space tradeoff.")
        ("O3", "Enable all optimizations improving the speed but can increase the size of the program.")
        ("fglobal-optimization", "Enable optimizer engine")
        ("fparameter-allocation", "Enable parameter allocation in register")
        ("fpeephole-optimization", "Enable peephole optimizer")
        ("fomit-frame-pointer", "Omit frame pointer from functions")
        ("finline-functions", "Enable inlining")
        ("fno-inline-functions", "Disable inlining")
        ("funroll-loops", "Enable Loop Unrolling")
        ("fcomplete-peel-loops", "Enable Complete Loop Peeling")
        ;

    options.add_options("Backend")
        ("log", "Define the logging", cxxopts::value<std::string>()->default_value("0"))
        ("q,quiet", "Do not print anything")
        ("v,verbose", "Make the compiler verbose")
        ("single-threaded", "Disable the multi-threaded optimization")
        ("time", "Activate the timing system")
        ("stats", "Activate the statistics system")
        ("input", "Input file", cxxopts::value<std::string>())
        ;
}

void init_descriptions(){
    po::options_description general("General options");
    general.add_options()
        ("help,h", "Generate this help message")
        ("assembly,S", "Generate only the assembly")
        ("keep,k", "Keep the assembly file")
        ("version", "Print the version of eddic")
        ("output,o", po::value<std::string>()->default_value("a.out"), "Set the name of the executable")

        ("debug,g", "Add debugging symbols")

        ("template-depth", po::value<std::string>()->default_value("100"), "Define the maximum template depth")

        ("32", "Force the compilation for 32 bits platform")
        ("64", "Force the compilation for 64 bits platform")

        ("warning-all", "Enable all the warning messages")
        ("warning-unused", "Warn about unused variables, parameters and functions")
        ("warning-cast", "Warn about useless casts")
        ("warning-effects", "Warn about statements without effect")
        ("warning-includes", "Warn about useless includes")
        ;

    po::options_description display("Display options");
    display.add_options()
        ("ast", "Print the Abstract Syntax Tree representation of the source")
        ("ast-raw", "Print the Abstract Syntax Tree representation of the source coming directly from the parser before any pass is run on the AST. ")
        ("ast-only", "Only print the Abstract Syntax Tree representation of the source (do not continue compilation after printing)")

        ("mtac", "Print the medium-level Three Address Code representation of the source")
        ("mtac-opt", "Print the medium-level Three Address Code representation of the source before any optimization has been performed")
        ("mtac-only", "Only print the medium-level Three Address Code representation of the source (do not continue compilation after printing)")

        ("ltac-pre", "Print the low-level Three Address Code representation of the source before allocation of registers")
        ("ltac-alloc", "Print the low-level Three Address Code representation of the source before optimization")
        ("ltac", "Print the final low-level Three Address Code representation of the source")
        ("ltac-only", "Only print the low-level Three Address Code representation of the source (do not continue compilation after printing)")
        ;

    po::options_description optimization("Optimization options");
    optimization.add_options()
        ("Opt,O", po::value<std::string>()->implicit_value("0")->default_value("2"), "Define the optimization level")
        ("O0", "Disable all optimizations")
        ("O1", "Enable low-level optimizations")
        ("O2", "Enable all optimizations improving the speed but do imply a space tradeoff.")
        ("O3", "Enable all optimizations improving the speed but can increase the size of the program.")

        ("fglobal-optimization", "Enable optimizer engine")
        ("fparameter-allocation", "Enable parameter allocation in register")
        ("fpeephole-optimization", "Enable peephole optimizer")
        ("fomit-frame-pointer", "Omit frame pointer from functions")
        ("finline-functions", "Enable inlining")
        ("fno-inline-functions", "Disable inlining")
        ("funroll-loops", "Enable Loop Unrolling")
        ("fcomplete-peel-loops", "Enable Complete Loop Peeling")
        ;

    po::options_description backend("Backend options");
    backend.add_options()
        ("log", po::value<std::string>()->default_value("0"), "Define the logging")
        ("quiet,q", "Do not print anything")
        ("verbose,v", "Make the compiler verbose")
        ("single-threaded", "Disable the multi-threaded optimization")
        ("time", "Activate the timing system")
        ("stats", "Activate the statistics system")
        ("input", po::value<std::string>(), "Input file")
        ;

    all.add(general).add(display).add(optimization).add(backend);
    visible.add(general).add(display).add(optimization);

    add_trigger("warning-all", {"warning-unused", "warning-cast", "warning-effects", "warning-includes"});

    //Special triggers for optimization levels
    add_trigger("__1", {"fpeephole-optimization"});
    add_trigger("__2", {"fglobal-optimization", "fomit-frame-pointer", "fparameter-allocation", "finline-functions"});
    add_trigger("__3", {"funroll-loops", "fcomplete-peel-loops", "funswitch-loops"});
}

inline void trigger_childs(std::shared_ptr<Configuration> configuration, const std::vector<std::string>& childs){
    for(auto& child : childs){
        configuration->values[child].defined = true;
        configuration->values[child].value = std::string("true");
    }
}

} //end of anonymous namespace

std::shared_ptr<Configuration> eddic::parseOptions(int argc, const char* argv[]) {
    //Create a new configuration
    auto configuration = std::make_shared<Configuration>();

    try {
        //Only if the description has not been already defined
        if(!description_flag.load()){
            bool old_value = description_flag.load();
            if(description_flag.compare_exchange_strong(old_value, true)){
                init_descriptions();
            }
        }

        cxxopts::Options options("eddic", "  source.eddi");

        init_options(options);

        options.parse_positional("input");

        auto& v = const_cast<char**&>(argv);
        options.parse(argc, v);

        //Add the option of the input file
        //po::positional_options_description p;
        //p.add("input", -1);

        ////Create a new set of options
        //po::variables_map options;

        ////Parse the command line options
        //po::store(po::command_line_parser(argc, argv).options(all).extra_parser(numeric_parser).positional(p).run(), options);
        //po::notify(options);

        //Transfer the options in the eddic configuration
        for(auto& option : all.options()){
            ConfigValue value;

            if(options.count(option->long_name())){
                value.defined = true;
                value.value = options[option->long_name()].as<std::string>();
            } else {
                value.defined = false;
                value.value = std::string("false");
            }

            configuration->values[option->long_name()] = value;
        }

        if(options.count("O0") + options.count("O1") + options.count("O2") > 1){
            std::cout << "Invalid command line options : only one optimization level should be set" << std::endl;

            return nullptr;
        }

        if(options.count("64") && options.count("32")){
            std::cout << "Invalid command line options : a compilation cannot be both 32 and 64 bits" << std::endl;

            return nullptr;
        }

        //Update optimization level based on special switches
        if(options.count("O0")){
            configuration->values["Opt"].value = "0";
        } else if(options.count("O1")){
            configuration->values["Opt"].value = "1";
        } else if(options.count("O2")){
            configuration->values["Opt"].value = "2";
        } else if(options.count("O3")){
            configuration->values["Opt"].value = "3";
        }

        //Triggers dependent options
        for(auto& trigger : triggers){
            if(configuration->option_defined(trigger.first)){
                trigger_childs(configuration, trigger.second);
            }
        }

        if(configuration->option_int_value("Opt") >= 1){
            trigger_childs(configuration, triggers["__1"]);
        }

        if(configuration->option_int_value("Opt") >= 2){
            trigger_childs(configuration, triggers["__2"]);
        }

        if(configuration->option_int_value("Opt") >= 3){
            trigger_childs(configuration, triggers["__3"]);
        }
    } catch (const po::ambiguous_option& e) {
        std::cout << "Invalid command line options: " << e.what() << std::endl;

        return nullptr;
    } catch (const po::unknown_option& e) {
        std::cout << "Invalid command line options: " << e.what() << std::endl;

        return nullptr;
    } catch (const po::multiple_occurrences& e) {
        std::cout << "Invalid command line options: Multiple occurrences of " << e.get_option_name() << std::endl;

        return nullptr;
    }

    return configuration;
}

bool Configuration::option_defined(const std::string& option_name){
    return values[option_name].defined;
}

std::string Configuration::option_value(const std::string& option_name){
    return values[option_name].value;
}

int Configuration::option_int_value(const std::string& option_name){
    return boost::lexical_cast<int>(values[option_name].value);
}

void eddic::print_help(){
    cxxopts::Options options("eddic", "  source.eddi");

    init_options(options);

    std::cout << options.help({"General", "Display", "Optimization"}) << std::endl;
}

void eddic::print_version(){
    std::cout << "eddic version 1.2.3" << std::endl;
}
<|endoftext|>


<commit_before>#include "Transition.h"
#include "RenderState.h"
#include "MaskedSprite.h"
#include "core/oxygine.h"
#include "flow.h"

#if OXYGINE_RENDERER>2
#   include "TweenAlphaFade.h"
#endif

namespace oxygine
{

    namespace flow
    {

        Transition::Transition() : _done(false), _singleDirection(false), _flow(0)
        {

        }

        void Transition::run(Flow* f, spScene current, spScene next, bool back)
        {
            _flow = f;
            _current = current;
            _next = next;
            _done = false;

            _attach(current, next, back);
            _run(current, next, back);
        }

        void Transition::waitTween(spTween t)
        {
            t->setDoneCallback([ = ](Event*)
            {
                _done = true;
                _clear();
                _current = 0;
                _next = 0;
                _flow->phaseEnd();
            });
        }

        void Transition::_attach(spScene current, spScene next, bool back)
        {
            if (current->_dialog)
            {
                if (!back)
                    getStage()->insertChildAfter(next->_holder, current->_holder);
            }
            else
            {
                if (back)
                    getStage()->insertChildBefore(next->_holder, current->_holder);
                else
                    getStage()->insertChildAfter(next->_holder, current->_holder);
            }
        }

        void Transition::_run(spScene current, spScene next, bool back)
        {
            _done = true;
        }

        void TransitionMove::assign(Scene* scene)
        {
            spTransition t = new TransitionMove;
            scene->setTransitionIn(t);
            scene->setTransitionOut(t);
        }

        TransitionMove::TransitionMove()
        {
            _fade = new ColorRectSprite;
            _fade->setPosition(-10000, -10000);
            _fade->setSize(Vector2(30000, 30000));
            _fade->setColor(Color(0, 0, 0, 128));
            //_fade->setAlpha(0);
        }

        void TransitionMove::_run(spScene current, spScene next, bool back)
        {
            Vector2 _src = Vector2(0.0f, -(float)getStage()->getHeight() + 0);
            Vector2 _dest = Vector2(0.0f, 0.0f);
            int _duration = 500;

            spScene target = back ? current : next;

            spActor holder = target->getHolder();
            if (back)
            {
                std::swap(_src, _dest);

                spTween t = _fade->addTween(Actor::TweenAlpha(0), _duration);
                t->setDetachActor(true);
            }
            else
            {
                _fade->setAlpha(0);
                _fade->addTween(Actor::TweenAlpha(255), _duration);
                holder->getParent()->insertChildBefore(_fade, holder);
            }

            holder->setPosition(_src);
            spTween tween = holder->addTween(Actor::TweenPosition(_dest), _duration, 1, false, 0, Tween::ease_inOutBack);
            waitTween(tween);
        }

        void TransitionFade::assign(Scene* scene)
        {
            spTransition t = new TransitionFade;
            scene->setTransitionIn(t);
            scene->setTransitionOut(t);
        }

        void TransitionFade::_run(spScene current, spScene next, bool back)
        {
            spScene target = back ? current : next;

            int duration = 500;
#if OXYGINE_RENDERER>2
            //target->getHolder()->setAlpha(back ? 255 : 0);
            spTween tween = target->getHolder()->addTween(
                                TweenAlphaFade(!back, TweenAlphaFade::opt_fullscreen), duration, 1, false, 0);
#else
            target->getHolder()->setAlpha(back ? 255 : 0);
            spTween tween = target->getHolder()->addTween(
                                Actor::TweenAlpha(back ? 0 : 255), duration, 1, false, 0);
#endif
            waitTween(tween);
        }

        TransitionShutters::TransitionShutters()
        {
            left = new ColorRectSprite;
            left->setWidth(getStage()->getWidth() / 2);
            left->setHeight(getStage()->getHeight());

            right = new ColorRectSprite;
            right->setWidth(getStage()->getWidth() / 2);
            right->setHeight(getStage()->getHeight());
        }

        void TransitionShutters::_attach(spScene current, spScene next, bool back)
        {

        }

        void TransitionShutters::_run(spScene current, spScene next, bool back)
        {
            getStage()->insertChildAfter(left, current->getHolder());
            getStage()->insertChildAfter(right, current->getHolder());

            int dur = 500;
            left->setX(-left->getWidth());
            right->setX(getStage()->getWidth());

            left->addTween(Actor::TweenX(0), dur);
            spTween t = right->addTween(Actor::TweenX(getStage()->getWidth() / 2), dur);
            t->setDoneCallback([ = ](Event*)
            {
                getStage()->insertChildAfter(next->getHolder(), current->getHolder());
                current->getHolder()->detach();

                left->addTween(Actor::TweenX(-left->getWidth()), dur);
                spTween a = right->addTween(Actor::TweenX(getStage()->getWidth()), dur);
                waitTween(a);
            });
        }

        void TransitionShutters::_clear()
        {
            left->detach();
            right->detach();
        }

        void TransitionShutters::assign(Scene* scene)
        {
            spTransition t = new TransitionShutters;
            scene->setTransitionIn(t);
            scene->setTransitionOut(t);
        }

        TransitionQuads::TransitionQuads() : _center(0, 0)
        {
            //_singleDirection = true;
            getStage()->addEventListener(TouchEvent::CLICK, CLOSURE(this, &TransitionQuads::clicked));
        }

        TransitionQuads::~TransitionQuads()
        {
            getStage()->removeEventListeners(this);
        }

        void TransitionQuads::assign(Scene* scene)
        {
            spTransition t = new TransitionQuads;
            scene->setTransitionIn(t);
            scene->setTransitionOut(t);
        }

        void TransitionQuads::clicked(Event* ev)
        {
            TouchEvent* te = (TouchEvent*)ev;
            _center = getStage()->local2global(te->localPosition);
        }

        void TransitionQuads::update(const UpdateState& us)
        {
            Color b(0, 0, 0, 0);

            Point ds = core::getDisplaySize();
            Rect vp(Point(0, 0), ds);

            IVideoDriver::instance->setRenderTarget(_mask);

#if OXYGINE_RENDERER>2

            Material::setCurrent(0);

            STDRenderer& r = *STDMaterial::instance->getRenderer();
            RenderState rs;
            rs.material = STDMaterial::instance;
            r.initCoordinateSystem(ds.x, ds.y, true);
            //TweenAlphaFade
            //r.Renderer::begin(0);

            {
                _holder->setPosition(Vector2(0, 0));
                _holder->setVisible(true);
                _holder->render(rs);
                //rs.material->render(_holder.get(), rs);
                _holder->setPosition(getStage()->global2local(Vector2(0, 0)));
                //_holder->setVisible(false);
                //r.end();
                rs.material->finish();
            }

#else

            RenderState rs;
            rs.renderer = &_r;

            _r.begin(0);
            {
                _holder->setPosition(Vector2(0, 0));
                _holder->setVisible(true);
                _holder->render(rs);
                _holder->setPosition(getStage()->global2local(Vector2(0, 0)));
                _holder->setVisible(false);
                _r.end();
            }
#endif

            IVideoDriver::instance->setRenderTarget(0);

        }

        void TransitionQuads::_run(spScene current, spScene next, bool back)
        {
            Point ds = core::getDisplaySize();
            spActor holder = new Actor;
            holder->setPosition(getStage()->global2local(Vector2(0, 0)));
            //holder->setVisible(false);
            holder->setSize(core::getDisplaySize());
            holder->attachTo(getStage());
            holder->setPriority(1000);

            int numX = ds.x / 40;
            int numY = ds.y / 40;

            //log::messageln("tq1");
            Vector2 quad(holder->getWidth() / numX, holder->getHeight() / numY);
            spTween slowestTween;

            for (int y = 0; y < numY; ++y)
            {
                for (int x = 0; x < numX; ++x)
                {
                    spSprite sp = new ColorRectSprite;
                    Vector2 pos(quad.x * x, quad.y * y);
                    pos += quad / 2;
                    sp->setPosition(pos);
                    sp->setAnchor(Vector2(0.5f, 0.5f));
                    sp->setSize(quad);
                    sp->attachTo(holder);
                    sp->setScale(0);
                    sp->setColor(Color(0xffffffff));
                    Vector2 d = pos - _center;
                    float time = d.length() / holder->getSize().length();
                    /*
                    if (back)
                    time = 1.0f - time;
                    */

                    float mp = 4.0f;
                    //mp = 10;
                    int tm = int(1 + time * 800 * mp);
                    spTween nt = sp->addTween(Actor::TweenScale(1.0f), int(100 * mp), 1, false, tm);
                    if (!slowestTween || (int)slowestTween->getDelay() < tm)
                        slowestTween = nt;
                }
            }

            //log::messageln("tq2");

#if OXYGINE_RENDERER <= 2

            STDRenderer r;
            RenderState rs;
            rs.renderer = &r;
            rs.renderer->initCoordinateSystem(ds.x, ds.y, true);

            spNativeTexture mask = IVideoDriver::instance->createTexture();
            mask->init(ds.x, ds.y, TF_R5G5B5A1, true);

            _mask = mask;

            spSprite maskSprite = new Sprite;
            {
                AnimationFrame fr;
                Diffuse df;
                df.base = mask;
                RectF srcRect(0, 0, (float)ds.x / mask->getWidth(), (float)ds.y / mask->getHeight());
                RectF destRect(Vector2(0, 0), ds);
                fr.init(0, df, srcRect, destRect, ds);
                maskSprite->setAnimFrame(fr);
            }

            //log::messageln("tq3");

            //#define BUG
            //STDMaterial
            spMaskedSprite bg = new MaskedSprite;
            bg->setMask(maskSprite);

            bg->attachTo(getStage());
            bg->setPriority(100);

            bg->addChild(next->getHolder());
            bg->setInputEnabled(false);
            _bg = bg;

            timeMS tm = getTimeMS() + 3000;

            holder->setCallbackDoUpdate(CLOSURE(this, &TransitionQuads::update));

            //_r = r;
            _holder = holder;
            waitTween(slowestTween);
#endif
        }

        void TransitionQuads::_clear()
        {
            _next->getHolder()->attachTo(getStage());

            _holder->detach();
            _bg->detach();
            _bg->setMask(0);

            _mask->release();
            _mask = 0;
        }
    }
}<commit_msg>minor<commit_after>#include "Transition.h"
#include "RenderState.h"
#include "MaskedSprite.h"
#include "core/oxygine.h"
#include "flow.h"
#include "STDMaterial.h"

#if OXYGINE_RENDERER>2
#   include "TweenAlphaFade.h"
#endif

namespace oxygine
{

    namespace flow
    {

        Transition::Transition() : _done(false), _singleDirection(false), _flow(0)
        {

        }

        void Transition::run(Flow* f, spScene current, spScene next, bool back)
        {
            _flow = f;
            _current = current;
            _next = next;
            _done = false;

            _attach(current, next, back);
            _run(current, next, back);
        }

        void Transition::waitTween(spTween t)
        {
            t->setDoneCallback([ = ](Event*)
            {
                _done = true;
                _clear();
                _current = 0;
                _next = 0;
                _flow->phaseEnd();
            });
        }

        void Transition::_attach(spScene current, spScene next, bool back)
        {
            if (current->_dialog)
            {
                if (!back)
                    getStage()->insertChildAfter(next->_holder, current->_holder);
            }
            else
            {
                if (back)
                    getStage()->insertChildBefore(next->_holder, current->_holder);
                else
                    getStage()->insertChildAfter(next->_holder, current->_holder);
            }
        }

        void Transition::_run(spScene current, spScene next, bool back)
        {
            _done = true;
        }

        void TransitionMove::assign(Scene* scene)
        {
            spTransition t = new TransitionMove;
            scene->setTransitionIn(t);
            scene->setTransitionOut(t);
        }

        TransitionMove::TransitionMove()
        {
            _fade = new ColorRectSprite;
            _fade->setPosition(-10000, -10000);
            _fade->setSize(Vector2(30000, 30000));
            _fade->setColor(Color(0, 0, 0, 128));
            //_fade->setAlpha(0);
        }

        void TransitionMove::_run(spScene current, spScene next, bool back)
        {
            Vector2 _src = Vector2(0.0f, -(float)getStage()->getHeight() + 0);
            Vector2 _dest = Vector2(0.0f, 0.0f);
            int _duration = 500;

            spScene target = back ? current : next;

            spActor holder = target->getHolder();
            if (back)
            {
                std::swap(_src, _dest);

                spTween t = _fade->addTween(Actor::TweenAlpha(0), _duration);
                t->setDetachActor(true);
            }
            else
            {
                _fade->setAlpha(0);
                _fade->addTween(Actor::TweenAlpha(255), _duration);
                holder->getParent()->insertChildBefore(_fade, holder);
            }

            holder->setPosition(_src);
            spTween tween = holder->addTween(Actor::TweenPosition(_dest), _duration, 1, false, 0, Tween::ease_inOutBack);
            waitTween(tween);
        }

        void TransitionFade::assign(Scene* scene)
        {
            spTransition t = new TransitionFade;
            scene->setTransitionIn(t);
            scene->setTransitionOut(t);
        }

        void TransitionFade::_run(spScene current, spScene next, bool back)
        {
            spScene target = back ? current : next;

            int duration = 500;
#if OXYGINE_RENDERER>3
			//target->getHolder()->setAlpha(back ? 255 : 0);
			spTween tween = target->getHolder()->addTween(
				TweenAlphaFade(!back, PostProcessOptions().fullscreen()), duration, 1, false, 0);
#elif OXYGINE_RENDERER>2
            //target->getHolder()->setAlpha(back ? 255 : 0);
            spTween tween = target->getHolder()->addTween(
                                TweenAlphaFade(!back, TweenAlphaFade::opt_fullscreen), duration, 1, false, 0);
#else
            target->getHolder()->setAlpha(back ? 255 : 0);
            spTween tween = target->getHolder()->addTween(
                                Actor::TweenAlpha(back ? 0 : 255), duration, 1, false, 0);
#endif
            waitTween(tween);
        }

        TransitionShutters::TransitionShutters()
        {
            left = new ColorRectSprite;
            left->setWidth(getStage()->getWidth() / 2);
            left->setHeight(getStage()->getHeight());

            right = new ColorRectSprite;
            right->setWidth(getStage()->getWidth() / 2);
            right->setHeight(getStage()->getHeight());
        }

        void TransitionShutters::_attach(spScene current, spScene next, bool back)
        {

        }

        void TransitionShutters::_run(spScene current, spScene next, bool back)
        {
            getStage()->insertChildAfter(left, current->getHolder());
            getStage()->insertChildAfter(right, current->getHolder());

            int dur = 500;
            left->setX(-left->getWidth());
            right->setX(getStage()->getWidth());

            left->addTween(Actor::TweenX(0), dur);
            spTween t = right->addTween(Actor::TweenX(getStage()->getWidth() / 2), dur);
            t->setDoneCallback([ = ](Event*)
            {
                getStage()->insertChildAfter(next->getHolder(), current->getHolder());
                current->getHolder()->detach();

                left->addTween(Actor::TweenX(-left->getWidth()), dur);
                spTween a = right->addTween(Actor::TweenX(getStage()->getWidth()), dur);
                waitTween(a);
            });
        }

        void TransitionShutters::_clear()
        {
            left->detach();
            right->detach();
        }

        void TransitionShutters::assign(Scene* scene)
        {
            spTransition t = new TransitionShutters;
            scene->setTransitionIn(t);
            scene->setTransitionOut(t);
        }

        TransitionQuads::TransitionQuads() : _center(0, 0)
        {
            //_singleDirection = true;
            getStage()->addEventListener(TouchEvent::CLICK, CLOSURE(this, &TransitionQuads::clicked));
        }

        TransitionQuads::~TransitionQuads()
        {
            getStage()->removeEventListeners(this);
        }

        void TransitionQuads::assign(Scene* scene)
        {
            spTransition t = new TransitionQuads;
            scene->setTransitionIn(t);
            scene->setTransitionOut(t);
        }

        void TransitionQuads::clicked(Event* ev)
        {
            TouchEvent* te = (TouchEvent*)ev;
            _center = getStage()->local2global(te->localPosition);
        }

        void TransitionQuads::update(const UpdateState& us)
        {
            Color b(0, 0, 0, 0);

            Point ds = core::getDisplaySize();
            Rect vp(Point(0, 0), ds);

            IVideoDriver::instance->setRenderTarget(_mask);

#if OXYGINE_RENDERER>2

            Material::setCurrent(0);

            STDRenderer& r = *STDMaterial::instance->getRenderer();
            RenderState rs;
            rs.material = STDMaterial::instance;
            r.initCoordinateSystem(ds.x, ds.y, true);
            //TweenAlphaFade
            //r.Renderer::begin(0);

            {
                _holder->setPosition(Vector2(0, 0));
                _holder->setVisible(true);
                _holder->render(rs);
                //rs.material->render(_holder.get(), rs);
                _holder->setPosition(getStage()->global2local(Vector2(0, 0)));
                //_holder->setVisible(false);
                //r.end();
                rs.material->finish();
            }

#else

            RenderState rs;
            rs.renderer = &_r;

            _r.begin(0);
            {
                _holder->setPosition(Vector2(0, 0));
                _holder->setVisible(true);
                _holder->render(rs);
                _holder->setPosition(getStage()->global2local(Vector2(0, 0)));
                _holder->setVisible(false);
                _r.end();
            }
#endif

            IVideoDriver::instance->setRenderTarget(0);

        }

        void TransitionQuads::_run(spScene current, spScene next, bool back)
        {
            Point ds = core::getDisplaySize();
            spActor holder = new Actor;
            holder->setPosition(getStage()->global2local(Vector2(0, 0)));
            //holder->setVisible(false);
            holder->setSize(core::getDisplaySize());
            holder->attachTo(getStage());
            holder->setPriority(1000);

            int numX = ds.x / 40;
            int numY = ds.y / 40;

            //log::messageln("tq1");
            Vector2 quad(holder->getWidth() / numX, holder->getHeight() / numY);
            spTween slowestTween;

            for (int y = 0; y < numY; ++y)
            {
                for (int x = 0; x < numX; ++x)
                {
                    spSprite sp = new ColorRectSprite;
                    Vector2 pos(quad.x * x, quad.y * y);
                    pos += quad / 2;
                    sp->setPosition(pos);
                    sp->setAnchor(Vector2(0.5f, 0.5f));
                    sp->setSize(quad);
                    sp->attachTo(holder);
                    sp->setScale(0);
                    sp->setColor(Color(0xffffffff));
                    Vector2 d = pos - _center;
                    float time = d.length() / holder->getSize().length();
                    /*
                    if (back)
                    time = 1.0f - time;
                    */

                    float mp = 4.0f;
                    //mp = 10;
                    int tm = int(1 + time * 800 * mp);
                    spTween nt = sp->addTween(Actor::TweenScale(1.0f), int(100 * mp), 1, false, tm);
                    if (!slowestTween || (int)slowestTween->getDelay() < tm)
                        slowestTween = nt;
                }
            }

            //log::messageln("tq2");

#if OXYGINE_RENDERER <= 2

            STDRenderer r;
            RenderState rs;
            rs.renderer = &r;
            rs.renderer->initCoordinateSystem(ds.x, ds.y, true);

            spNativeTexture mask = IVideoDriver::instance->createTexture();
            mask->init(ds.x, ds.y, TF_R5G5B5A1, true);

            _mask = mask;

            spSprite maskSprite = new Sprite;
            {
                AnimationFrame fr;
                Diffuse df;
                df.base = mask;
                RectF srcRect(0, 0, (float)ds.x / mask->getWidth(), (float)ds.y / mask->getHeight());
                RectF destRect(Vector2(0, 0), ds);
                fr.init(0, df, srcRect, destRect, ds);
                maskSprite->setAnimFrame(fr);
            }

            //log::messageln("tq3");

            //#define BUG
            //STDMaterial
            spMaskedSprite bg = new MaskedSprite;
            bg->setMask(maskSprite);

            bg->attachTo(getStage());
            bg->setPriority(100);

            bg->addChild(next->getHolder());
            bg->setInputEnabled(false);
            _bg = bg;

            timeMS tm = getTimeMS() + 3000;

            holder->setCallbackDoUpdate(CLOSURE(this, &TransitionQuads::update));

            //_r = r;
            _holder = holder;
            waitTween(slowestTween);
#endif
        }

        void TransitionQuads::_clear()
        {
            _next->getHolder()->attachTo(getStage());

            _holder->detach();
            _bg->detach();
            _bg->setMask(0);

            _mask->release();
            _mask = 0;
        }
    }
}<|endoftext|>


<commit_before>/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                    _______    _                                     *
 *                   (  ____ \  ( \     |\     /|                      *
 *                   | (    \/  | (     ( \   / )                      *
 *                   | (__      | |      \ (_) /                       *
 *                   |  __)     | |       \   /                        *
 *                   | (        | |        ) (                         *
 *                   | )        | (____/\  | |                         *
 *                   |/         (_______/  \_/                         *
 *                                                                     *
 *                                                                     *
 *     fly is an awesome c++11 network library.                        *
 *                                                                     *
 *   @author: lichuan                                                  *
 *   @qq: 308831759                                                    *
 *   @email: 308831759@qq.com                                          *
 *   @github: https://github.com/lichuan/fly                           *
 *   @date: 2015-06-10 17:27:54                                        *
 *                                                                     *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#ifndef FLY__BASE__LOGGER
#define FLY__BASE__LOGGER

#include <cstdio>
#include <atomic>
#include <string>
#include <mutex>
#include <sys/time.h>
#include "fly/base/common.hpp"
#include "fly/base/singleton.hpp"

namespace fly {
namespace base {

enum LOG_LEVEL
{
    DEBUG,
    INFO,
    WARN,
    ERROR,
    FATAL
};

class Logger : public Singleton<Logger>
{
public:
    void init(LOG_LEVEL level, const std::string &app, const std::string &path);
    void _log(uint32 year, uint32 month, uint32 day, const char *format, ...);

    bool _enter(LOG_LEVEL level)
    {
        if(level < m_level)
        {
            return false;
        }

        m_enter_num.fetch_add(1, std::memory_order_relaxed);

        return true;
    }

private:
    LOG_LEVEL m_level;
    std::string m_file_name;
    std::string m_file_full_name;
    FILE *m_file;
    std::atomic<uint32> m_year;
    std::atomic<uint32> m_month;
    std::atomic<uint32> m_day;
    std::atomic<uint32> m_enter_num {0};
    std::mutex m_mutex;
};

}
}

#define LOG_DEBUG(format, ...) \
    if(fly::base::Logger::instance()->_enter(fly::base::DEBUG)) \
    { \
        char _format[1024]; \
        struct timeval _tv; \
        gettimeofday(&_tv, NULL); \
        struct tm _tm; \
        localtime_r(&_tv.tv_sec, &_tm); \
        sprintf(_format, "%d-%02d-%02d %02d:%02d:%02d.%06ld |debug| %s:%d {%s}\n", 1900 + _tm.tm_year, 1 + _tm.tm_mon, _tm.tm_mday, _tm.tm_hour, \
                _tm.tm_min, _tm.tm_sec, _tv.tv_usec, __FILE__, __LINE__, format); \
        fly::base::Logger::instance()->_log(1900 + _tm.tm_year, 1 + _tm.tm_mon, _tm.tm_mday, _format, ##__VA_ARGS__); \
    }

#define LOG_INFO(format, ...) \
    if(fly::base::Logger::instance()->_enter(fly::base::INFO)) \
    { \
        char _format[1024]; \
        struct timeval _tv; \
        gettimeofday(&_tv, NULL); \
        struct tm _tm; \
        localtime_r(&_tv.tv_sec, &_tm); \
        sprintf(_format, "%d-%02d-%02d %02d:%02d:%02d.%06ld |info| %s:%d {%s}\n", 1900 + _tm.tm_year, 1 + _tm.tm_mon, _tm.tm_mday, _tm.tm_hour, \
                _tm.tm_min, _tm.tm_sec, _tv.tv_usec, __FILE__, __LINE__, format); \
        fly::base::Logger::instance()->_log(1900 + _tm.tm_year, 1 + _tm.tm_mon, _tm.tm_mday, _format, ##__VA_ARGS__); \
    }

#define LOG_WARN(format, ...) \
    if(fly::base::Logger::instance()->_enter(fly::base::WARN)) \
    { \
        char _format[1024]; \
        struct timeval _tv; \
        gettimeofday(&_tv, NULL); \
        struct tm _tm; \
        localtime_r(&_tv.tv_sec, &_tm); \
        sprintf(_format, "%d-%02d-%02d %02d:%02d:%02d.%06ld |warn| %s:%d {%s}\n", 1900 + _tm.tm_year, 1 + _tm.tm_mon, _tm.tm_mday, _tm.tm_hour, \
                _tm.tm_min, _tm.tm_sec, _tv.tv_usec, __FILE__, __LINE__, format); \
        fly::base::Logger::instance()->_log(1900 + _tm.tm_year, 1 + _tm.tm_mon, _tm.tm_mday, _format, ##__VA_ARGS__); \
    }

#define LOG_ERROR(format, ...) \
    if(fly::base::Logger::instance()->_enter(fly::base::ERROR)) \
    { \
        char _format[1024]; \
        struct timeval _tv; \
        gettimeofday(&_tv, NULL); \
        struct tm _tm; \
        localtime_r(&_tv.tv_sec, &_tm); \
        sprintf(_format, "%d-%02d-%02d %02d:%02d:%02d.%06ld |error| %s:%d {%s}\n", 1900 + _tm.tm_year, 1 + _tm.tm_mon, _tm.tm_mday, _tm.tm_hour, \
                _tm.tm_min, _tm.tm_sec, _tv.tv_usec, __FILE__, __LINE__, format); \
        fly::base::Logger::instance()->_log(1900 + _tm.tm_year, 1 + _tm.tm_mon, _tm.tm_mday, _format, ##__VA_ARGS__); \
    }

#define LOG_FATAL(format, ...) \
    if(fly::base::Logger::instance()->_enter(fly::base::FATAL)) \
    { \
        char _format[1024]; \
        struct timeval _tv; \
        gettimeofday(&_tv, NULL); \
        struct tm _tm; \
        localtime_r(&_tv.tv_sec, &_tm); \
        sprintf(_format, "%d-%02d-%02d %02d:%02d:%02d.%06ld |fatal| %s:%d {%s}\n", 1900 + _tm.tm_year, 1 + _tm.tm_mon, _tm.tm_mday, _tm.tm_hour, \
                _tm.tm_min, _tm.tm_sec, _tv.tv_usec, __FILE__, __LINE__, format); \
        fly::base::Logger::instance()->_log(1900 + _tm.tm_year, 1 + _tm.tm_mon, _tm.tm_mday, _format, ##__VA_ARGS__); \
    }

#endif
<commit_msg>add utc in logger<commit_after>/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                    _______    _                                     *
 *                   (  ____ \  ( \     |\     /|                      *
 *                   | (    \/  | (     ( \   / )                      *
 *                   | (__      | |      \ (_) /                       *
 *                   |  __)     | |       \   /                        *
 *                   | (        | |        ) (                         *
 *                   | )        | (____/\  | |                         *
 *                   |/         (_______/  \_/                         *
 *                                                                     *
 *                                                                     *
 *     fly is an awesome c++11 network library.                        *
 *                                                                     *
 *   @author: lichuan                                                  *
 *   @qq: 308831759                                                    *
 *   @email: 308831759@qq.com                                          *
 *   @github: https://github.com/lichuan/fly                           *
 *   @date: 2015-06-10 17:27:54                                        *
 *                                                                     *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#ifndef FLY__BASE__LOGGER
#define FLY__BASE__LOGGER

#include <cstdio>
#include <atomic>
#include <string>
#include <mutex>
#include <sys/time.h>
#include "fly/base/common.hpp"
#include "fly/base/singleton.hpp"

namespace fly {
namespace base {

enum LOG_LEVEL
{
    DEBUG,
    INFO,
    WARN,
    ERROR,
    FATAL
};

class Logger : public Singleton<Logger>
{
public:
    void init(LOG_LEVEL level, const std::string &app, const std::string &path);
    void _log(uint32 year, uint32 month, uint32 day, const char *format, ...);

    bool _enter(LOG_LEVEL level)
    {
        if(level < m_level)
        {
            return false;
        }

        m_enter_num.fetch_add(1, std::memory_order_relaxed);

        return true;
    }

private:
    LOG_LEVEL m_level;
    std::string m_file_name;
    std::string m_file_full_name;
    FILE *m_file;
    std::atomic<uint32> m_year;
    std::atomic<uint32> m_month;
    std::atomic<uint32> m_day;
    std::atomic<uint32> m_enter_num {0};
    std::mutex m_mutex;
};

}
}

#define LOG_DEBUG(format, ...) \
    if(fly::base::Logger::instance()->_enter(fly::base::DEBUG)) \
    { \
        char _format[256]; \
        struct timeval _tv; \
        gettimeofday(&_tv, NULL); \
        struct tm _tm; \
        localtime_r(&_tv.tv_sec, &_tm); \
        sprintf(_format, "%d-%02d-%02d %02d:%02d:%02d.%06ld [utc:%lu] |debug| %s:%d {%s}\n", 1900 + _tm.tm_year, 1 + _tm.tm_mon, _tm.tm_mday, _tm.tm_hour, \
                _tm.tm_min, _tm.tm_sec, _tv.tv_usec, _tv.tv_sec, __FILE__, __LINE__, format); \
        fly::base::Logger::instance()->_log(1900 + _tm.tm_year, 1 + _tm.tm_mon, _tm.tm_mday, _format, ##__VA_ARGS__); \
    }

#define LOG_INFO(format, ...) \
    if(fly::base::Logger::instance()->_enter(fly::base::INFO)) \
    { \
        char _format[256]; \
        struct timeval _tv; \
        gettimeofday(&_tv, NULL); \
        struct tm _tm; \
        localtime_r(&_tv.tv_sec, &_tm); \
        sprintf(_format, "%d-%02d-%02d %02d:%02d:%02d.%06ld [utc:%lu] |info| %s:%d {%s}\n", 1900 + _tm.tm_year, 1 + _tm.tm_mon, _tm.tm_mday, _tm.tm_hour, \
                _tm.tm_min, _tm.tm_sec, _tv.tv_usec, _tv.tv_sec, __FILE__, __LINE__, format); \
        fly::base::Logger::instance()->_log(1900 + _tm.tm_year, 1 + _tm.tm_mon, _tm.tm_mday, _format, ##__VA_ARGS__); \
    }

#define LOG_WARN(format, ...) \
    if(fly::base::Logger::instance()->_enter(fly::base::WARN)) \
    { \
        char _format[256]; \
        struct timeval _tv; \
        gettimeofday(&_tv, NULL); \
        struct tm _tm; \
        localtime_r(&_tv.tv_sec, &_tm); \
        sprintf(_format, "%d-%02d-%02d %02d:%02d:%02d.%06ld [utc:%lu] |warn| %s:%d {%s}\n", 1900 + _tm.tm_year, 1 + _tm.tm_mon, _tm.tm_mday, _tm.tm_hour, \
                _tm.tm_min, _tm.tm_sec, _tv.tv_usec, _tv.tv_sec, __FILE__, __LINE__, format); \
        fly::base::Logger::instance()->_log(1900 + _tm.tm_year, 1 + _tm.tm_mon, _tm.tm_mday, _format, ##__VA_ARGS__); \
    }

#define LOG_ERROR(format, ...) \
    if(fly::base::Logger::instance()->_enter(fly::base::ERROR)) \
    { \
        char _format[256]; \
        struct timeval _tv; \
        gettimeofday(&_tv, NULL); \
        struct tm _tm; \
        localtime_r(&_tv.tv_sec, &_tm); \
        sprintf(_format, "%d-%02d-%02d %02d:%02d:%02d.%06ld [utc:%lu] |error| %s:%d {%s}\n", 1900 + _tm.tm_year, 1 + _tm.tm_mon, _tm.tm_mday, _tm.tm_hour, \
                _tm.tm_min, _tm.tm_sec, _tv.tv_usec, _tv.tv_sec, __FILE__, __LINE__, format); \
        fly::base::Logger::instance()->_log(1900 + _tm.tm_year, 1 + _tm.tm_mon, _tm.tm_mday, _format, ##__VA_ARGS__); \
    }

#define LOG_FATAL(format, ...) \
    if(fly::base::Logger::instance()->_enter(fly::base::FATAL)) \
    { \
        char _format[256]; \
        struct timeval _tv; \
        gettimeofday(&_tv, NULL); \
        struct tm _tm; \
        localtime_r(&_tv.tv_sec, &_tm); \
        sprintf(_format, "%d-%02d-%02d %02d:%02d:%02d.%06ld [utc:%lu] |fatal| %s:%d {%s}\n", 1900 + _tm.tm_year, 1 + _tm.tm_mon, _tm.tm_mday, _tm.tm_hour, \
                _tm.tm_min, _tm.tm_sec, _tv.tv_usec, _tv.tv_sec, __FILE__, __LINE__, format); \
        fly::base::Logger::instance()->_log(1900 + _tm.tm_year, 1 + _tm.tm_mon, _tm.tm_mday, _format, ##__VA_ARGS__); \
    }

#endif
<|endoftext|>