diff --git a/.dockerignore b/.dockerignore new file mode 120000 index 0000000..3e4e48b --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +.gitignore \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..0fd1239 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,12 @@ +sudo: required + +language: cpp + +services: + - docker + + +script: docker build . -f extra/docker/Dockerfile.Ubuntu16.04.build -t oastat_static_web_test + +notifications: + email: false diff --git a/CMakeLists.txt b/CMakeLists.txt index 0cf8bf7..7f24100 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,10 @@ cmake_minimum_required(VERSION 2.8.9) project (oastat_static_web_generator) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++11") +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_DEBUG} -g -DDEBUG") +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELEASE} -O2") + find_package(Boost COMPONENTS program_options REQUIRED) add_executable(oastat_static_web_generator src/oastat_static_web_generator.cpp) TARGET_LINK_LIBRARIES( oastat_static_web_generator ${Boost_LIBRARIES} cppdb ctemplate ) diff --git a/extra/docker/Dockerfile.Ubuntu16.04.build b/extra/docker/Dockerfile.Ubuntu16.04.build new file mode 100644 index 0000000..d7243c6 --- /dev/null +++ b/extra/docker/Dockerfile.Ubuntu16.04.build @@ -0,0 +1,9 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y build-essential libboost-dev libboost-program-options-dev libboost-filesystem-dev libboost-system-dev libboost-test-dev cmake libcppdb-dev libctemplate-dev + +RUN mkdir -p /staging + +COPY . /staging + +RUN cd /staging && cmake . && make diff --git a/run_and_open.sh b/run_and_open.sh new file mode 100755 index 0000000..fd88db0 --- /dev/null +++ b/run_and_open.sh @@ -0,0 +1,2 @@ +./oastat_static_web_generator --output-dir output +xdg-open output/index.html diff --git a/src/oastat_static_web_generator.cpp b/src/oastat_static_web_generator.cpp index 70148e5..673b4fa 100644 --- a/src/oastat_static_web_generator.cpp +++ b/src/oastat_static_web_generator.cpp @@ -17,6 +17,38 @@ CommandArguments cmdargs; const char* const SAGO_CONNECTION_STRING = "SAGO_CONNECTION_STRING"; +// means of death +typedef enum { + MOD_UNKNOWN, + MOD_SHOTGUN, + MOD_GAUNTLET, + MOD_MACHINEGUN, + MOD_GRENADE, + MOD_GRENADE_SPLASH, + MOD_ROCKET, + MOD_ROCKET_SPLASH, + MOD_PLASMA, + MOD_PLASMA_SPLASH, + MOD_RAILGUN, + MOD_LIGHTNING, + MOD_BFG, + MOD_BFG_SPLASH, + MOD_WATER, + MOD_SLIME, + MOD_LAVA, + MOD_CRUSH, + MOD_TELEFRAG, + MOD_FALLING, + MOD_SUICIDE, + MOD_TARGET_LASER, + MOD_TRIGGER_HURT, + MOD_NAIL, + MOD_CHAINGUN, + MOD_PROXIMITY_MINE, + MOD_KAMIKAZE, + MOD_JUICED, + MOD_GRAPPLE +} meansOfDeath_t; #define AWARD_IMPRESSIVE 2 #define AWARD_EXCELLENT 1 @@ -71,6 +103,7 @@ std::string getTimeStamp(const tm& _datetime) static std::map kills_by_player; static std::map player_deaths; static std::map> player_awards; +static std::map> player_weapon_kills; void populate_player_deaths(cppdb::session& database, const std::vector& player_ids) { std::string sql = "select count(0) from oastat.oastat_kills k where k.attacker <> k.target and target = ?"; @@ -101,6 +134,21 @@ void populate_player_awards(cppdb::session& database, const std::vector& pl } } +void populate_player_kills(cppdb::session& database, const std::vector& player_ids) { + std::string sql = "select modtype, count(0) c from oastat.oastat_kills where attacker <> target and attacker = ? group by modtype"; + cppdb::statement st = database.prepare(sql); + for (int player_id : player_ids) { + st.bind(1, player_id); + int weapon; + int count; + cppdb::result res = st.query(); + while (res.next()) { + res >> weapon >> count; + player_weapon_kills[player_id][weapon] = count; + } + } +} + std::vector get_top_killers(cppdb::session& database, int count) { std::vector ret; std::string sql = "select p.playerid, count(0) c from oastat.oastat_players p, oastat.oastat_kills k where p.playerid = k.attacker and k.attacker <> k.target and p.playerid <> 0 group by p.playerid order by c desc limit ?"; @@ -149,6 +197,7 @@ void write_html_index(cppdb::session& database) { std::vector player_list = get_top_killers(database, 25); populate_player_deaths(database, player_list); populate_player_awards(database, player_list); + populate_player_kills(database, player_list); for (int i = 0; i < player_list.size(); ++i) { OastatPlayer p = getPlayer(database, player_list.at(i)); ctemplate::TemplateDictionary* sub_dict = index_tpl.AddSectionDictionary("PLAYER_LIST"); @@ -165,6 +214,25 @@ void write_html_index(cppdb::session& database) { sub_dict->SetValue("AWARD_DEFENCE", std::to_string(player_awards[p.playerid][AWARD_DEFENCE])); sub_dict->SetValue("AWARD_ASSIST", std::to_string(player_awards[p.playerid][AWARD_ASSIST])); } + for (int i = 0; i < player_list.size(); ++i) { + OastatPlayer p = getPlayer(database, player_list.at(i)); + ctemplate::TemplateDictionary* sub_dict = index_tpl.AddSectionDictionary("PLAYER_WEAPON_LIST"); + sub_dict->SetValue("EVEN_LINE", (i%2)?"1":"0"); + sub_dict->SetValue("PLAYER_NAME", p.nickname); + sub_dict->SetValue("WEAPON_SHOTGUN", std::to_string(player_weapon_kills[p.playerid][MOD_SHOTGUN])); + sub_dict->SetValue("WEAPON_GAUNTLET", std::to_string(player_weapon_kills[p.playerid][MOD_GAUNTLET])); + sub_dict->SetValue("WEAPON_MACHINEGUN", std::to_string(player_weapon_kills[p.playerid][MOD_MACHINEGUN])); + sub_dict->SetValue("WEAPON_GRENADE", std::to_string(player_weapon_kills[p.playerid][MOD_GRENADE]+player_weapon_kills[p.playerid][MOD_GRENADE_SPLASH])); + sub_dict->SetValue("WEAPON_ROCKET", std::to_string(player_weapon_kills[p.playerid][MOD_ROCKET]+player_weapon_kills[p.playerid][MOD_ROCKET_SPLASH])); + sub_dict->SetValue("WEAPON_PLASMA", std::to_string(player_weapon_kills[p.playerid][MOD_PLASMA]+player_weapon_kills[p.playerid][MOD_PLASMA_SPLASH])); + sub_dict->SetValue("WEAPON_RAILGUN", std::to_string(player_weapon_kills[p.playerid][MOD_RAILGUN])); + sub_dict->SetValue("WEAPON_LIGHTNING", std::to_string(player_weapon_kills[p.playerid][MOD_LIGHTNING])); + sub_dict->SetValue("WEAPON_NAILGUN", std::to_string(player_weapon_kills[p.playerid][MOD_NAIL])); + sub_dict->SetValue("WEAPON_CHAINGUN", std::to_string(player_weapon_kills[p.playerid][MOD_CHAINGUN])); + sub_dict->SetValue("WEAPON_BFG", std::to_string(player_weapon_kills[p.playerid][MOD_BFG]+player_weapon_kills[p.playerid][MOD_BFG_SPLASH])); + sub_dict->SetValue("WEAPON_TELEFRAG", std::to_string(player_weapon_kills[p.playerid][MOD_TELEFRAG])); + sub_dict->SetValue("WEAPON_FALLING", std::to_string(player_weapon_kills[p.playerid][MOD_FALLING])); + } std::string output; ctemplate::ExpandTemplate("templates/index.tpl", ctemplate::DO_NOT_STRIP, &index_tpl, &output); std::ofstream myfile; diff --git a/templates/index.tpl b/templates/index.tpl index 0986dd7..b9f2ecf 100644 --- a/templates/index.tpl +++ b/templates/index.tpl @@ -48,6 +48,41 @@ {{/PLAYER_LIST}} + + + + + + + + + + + + + + + + + + {{#PLAYER_WEAPON_LIST}} + + + + + + + + + + + + + + + + + {{/PLAYER_WEAPON_LIST}}
Name
Shotgun
Gauntlet
Machinegun
Grenade
Rocket
Plasma
Railgun
Lightning
Nailgun
Chaingun
BFG
Telefrag
Falling
{{PLAYER_NAME}}
{{WEAPON_SHOTGUN}}
{{WEAPON_GAUNTLET}}
{{WEAPON_MACHINEGUN}}
{{WEAPON_GRENADE}}
{{WEAPON_ROCKET}}
{{WEAPON_PLASMA}}
{{WEAPON_RAILGUN}}
{{WEAPON_LIGHTNING}}
{{WEAPON_NAILGUN}}
{{WEAPON_CHAINGUN}}
{{WEAPON_BFG}}
{{WEAPON_TELEFRAG}}
{{WEAPON_FALLING}}