Implemented PvP&PvE tab & endpoint

This commit is contained in:
Rsl1122 2019-07-07 10:18:45 +03:00
parent 25b036aff2
commit 9240a4e4fa
7 changed files with 255 additions and 42 deletions

View File

@ -120,9 +120,10 @@ public class KillQueries {
AND + KillsTable.DATE + ">=?" +
AND + KillsTable.DATE + "<=?" +
GROUP_BY + KillsTable.VICTIM_UUID;
String sql = SELECT + "AVG(kills/deaths) as kdr" +
String sql = SELECT + "AVG(CAST(kills AS FLOAT)/CAST(deaths AS FLOAT)) as kdr" +
FROM + '(' + selectKillCounts + ") q1" +
INNER_JOIN + '(' + selectDeathCounts + ") q2 on q1." + KillsTable.KILLER_UUID + "=q2." + KillsTable.VICTIM_UUID;
INNER_JOIN + '(' + selectDeathCounts + ") q2 on q1." + KillsTable.KILLER_UUID + "=q2." + KillsTable.VICTIM_UUID +
WHERE + "deaths!=0";
return new QueryStatement<Double>(sql) {
@Override
@ -183,4 +184,33 @@ public class KillQueries {
}
};
}
public static Query<List<String>> topWeapons(long after, long before, UUID serverUUID, int limit) {
String innerSQL = SELECT + KillsTable.WEAPON + ", COUNT(1) as kills" +
FROM + KillsTable.TABLE_NAME +
WHERE + KillsTable.SERVER_UUID + "=?" +
AND + KillsTable.DATE + ">=?" +
AND + KillsTable.DATE + "<=?" +
GROUP_BY + KillsTable.WEAPON;
String sql = SELECT + KillsTable.WEAPON +
FROM + '(' + innerSQL + ')' +
ORDER_BY + "kills DESC LIMIT ?";
return new QueryStatement<List<String>>(sql, limit) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, serverUUID.toString());
statement.setLong(2, after);
statement.setLong(3, before);
statement.setInt(4, limit);
}
@Override
public List<String> processResults(ResultSet set) throws SQLException {
List<String> weapons = new ArrayList<>();
while (set.next()) weapons.add(set.getString(KillsTable.WEAPON));
return weapons;
}
};
}
}

View File

@ -0,0 +1,124 @@
/*
* This file is part of Player Analytics (Plan).
*
* Plan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License v3 as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Plan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
*/
package com.djrapitops.plan.system.json;
import com.djrapitops.plan.db.Database;
import com.djrapitops.plan.db.access.queries.objects.KillQueries;
import com.djrapitops.plan.system.database.DBSystem;
import com.djrapitops.plan.utilities.formatting.Formatter;
import com.djrapitops.plan.utilities.formatting.Formatters;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* Parses JSON payload for /server-page PvP & PvE tab.
*
* @author Rsl1122
*/
@Singleton
public class PvPPvEJSONParser {
private DBSystem dbSystem;
private Formatter<Double> decimalFormatter;
@Inject
public PvPPvEJSONParser(
DBSystem dbSystem,
Formatters formatters
) {
this.dbSystem = dbSystem;
decimalFormatter = formatters.decimals();
}
public Map<String, Object> createJSONAsMap(UUID serverUUID) {
Map<String, Object> serverOverview = new HashMap<>();
serverOverview.put("numbers", createNumbersMap(serverUUID));
serverOverview.put("insights", createInsightsMap(serverUUID));
return serverOverview;
}
private Map<String, Object> createNumbersMap(UUID serverUUID) {
Database db = dbSystem.getDatabase();
long now = System.currentTimeMillis();
long weekAgo = now - TimeUnit.DAYS.toMillis(7L);
long monthAgo = now - TimeUnit.DAYS.toMillis(30L);
Map<String, Object> numbers = new HashMap<>();
Long pks = db.query(KillQueries.playerKillCount(0L, now, serverUUID));
Long pks7d = db.query(KillQueries.playerKillCount(weekAgo, now, serverUUID));
Long pks30d = db.query(KillQueries.playerKillCount(monthAgo, now, serverUUID));
numbers.put("player_kills_total", pks);
numbers.put("player_kills_30d", pks30d);
numbers.put("player_kills_7d", pks7d);
numbers.put("player_kdr_avg", decimalFormatter.apply(db.query(KillQueries.averageKDR(0L, now, serverUUID))));
numbers.put("player_kdr_avg_30d", decimalFormatter.apply(db.query(KillQueries.averageKDR(monthAgo, now, serverUUID))));
numbers.put("player_kdr_avg_7d", decimalFormatter.apply(db.query(KillQueries.averageKDR(weekAgo, now, serverUUID))));
Long mobKills = db.query(KillQueries.mobKillCount(0L, now, serverUUID));
Long mobKills30d = db.query(KillQueries.mobKillCount(monthAgo, now, serverUUID));
Long mobKills7d = db.query(KillQueries.mobKillCount(weekAgo, now, serverUUID));
numbers.put("mob_kills_total", mobKills);
numbers.put("mob_kills_30d", mobKills30d);
numbers.put("mob_kills_7d", mobKills7d);
Long deaths = db.query(KillQueries.deathCount(0L, now, serverUUID));
Long deaths30d = db.query(KillQueries.deathCount(monthAgo, now, serverUUID));
Long deaths7d = db.query(KillQueries.deathCount(weekAgo, now, serverUUID));
numbers.put("deaths_total", deaths);
numbers.put("deaths_30d", deaths30d);
numbers.put("deaths_7d", deaths7d);
long mobDeaths = deaths - pks;
long mobDeaths30d = deaths30d - pks30d;
long mobDeaths7d = deaths7d - pks7d;
numbers.put("mob_deaths_total", mobDeaths);
numbers.put("mob_deaths_30d", mobDeaths30d);
numbers.put("mob_deaths_7d", mobDeaths7d);
numbers.put("mob_kdr_total", mobDeaths != 0 ? mobKills * 1.0 / mobDeaths : mobKills);
numbers.put("mob_kdr_30d", mobDeaths30d != 0 ? mobKills30d * 1.0 / mobDeaths30d : mobKills30d);
numbers.put("mob_kdr_7d", mobDeaths7d != 0 ? mobKills7d * 1.0 / mobDeaths7d : mobKills7d);
return numbers;
}
private Map<String, Object> createInsightsMap(UUID serverUUID) {
Database db = dbSystem.getDatabase();
long now = System.currentTimeMillis();
long monthAgo = now - TimeUnit.DAYS.toMillis(30L);
Map<String, Object> insights = new HashMap<>();
List<String> top3Weapons = db.query(KillQueries.topWeapons(monthAgo, now, serverUUID, 3));
insights.put("weapon_1st", getWeapon(top3Weapons, 0).orElse("-"));
insights.put("weapon_2nd", getWeapon(top3Weapons, 1).orElse("-"));
insights.put("weapon_3rd", getWeapon(top3Weapons, 2).orElse("-"));
return insights;
}
private <T> Optional<T> getWeapon(List<T> list, int index) {
return list.size() <= index ? Optional.empty() : Optional.of(list.get(index));
}
}

View File

@ -0,0 +1,64 @@
/*
* This file is part of Player Analytics (Plan).
*
* Plan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License v3 as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Plan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
*/
package com.djrapitops.plan.system.webserver.pages.json;
import com.djrapitops.plan.api.exceptions.WebUserAuthException;
import com.djrapitops.plan.api.exceptions.connection.WebException;
import com.djrapitops.plan.system.Identifiers;
import com.djrapitops.plan.system.json.PvPPvEJSONParser;
import com.djrapitops.plan.system.webserver.Request;
import com.djrapitops.plan.system.webserver.RequestTarget;
import com.djrapitops.plan.system.webserver.auth.Authentication;
import com.djrapitops.plan.system.webserver.pages.PageHandler;
import com.djrapitops.plan.system.webserver.response.Response;
import com.djrapitops.plan.system.webserver.response.data.JSONResponse;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.UUID;
/**
* JSON handler for PvP & PvE tab JSON requests.
*
* @author Rsl1122
*/
@Singleton
public class PvPPvEJSONHandler implements PageHandler {
private final Identifiers identifiers;
private final PvPPvEJSONParser jsonParser;
@Inject
public PvPPvEJSONHandler(
Identifiers identifiers,
PvPPvEJSONParser jsonParser
) {
this.identifiers = identifiers;
this.jsonParser = jsonParser;
}
@Override
public Response getResponse(Request request, RequestTarget target) throws WebException {
UUID serverUUID = identifiers.getServerUUID(target); // Can throw BadRequestException
return new JSONResponse<>(jsonParser.createJSONAsMap(serverUUID));
}
@Override
public boolean isAuthorized(Authentication auth, RequestTarget target) throws WebUserAuthException {
return auth.getWebUser().getPermLevel() <= 0;
}
}

View File

@ -42,7 +42,8 @@ public class RootJSONHandler extends TreePageHandler {
ServerOverviewJSONHandler serverOverviewJSONHandler,
OnlineActivityOverviewJSONHandler onlineActivityOverviewJSONHandler,
SessionsOverviewJSONHandler sessionsOverviewJSONHandler,
PlayerKillsJSONHandler playerKillsJSONHandler
PlayerKillsJSONHandler playerKillsJSONHandler,
PvPPvEJSONHandler pvppveJSONHandler
) {
super(responseFactory);
@ -53,6 +54,7 @@ public class RootJSONHandler extends TreePageHandler {
registerPage("serverOverview", serverOverviewJSONHandler);
registerPage("onlineOverview", onlineActivityOverviewJSONHandler);
registerPage("sessionsOverview", sessionsOverviewJSONHandler);
registerPage("playerVersus", pvppveJSONHandler);
}
@Override

View File

@ -212,9 +212,9 @@ function loadPvPPvEValues(json, error) {
$(element).find('#data_player_kills_30d').text(data.player_kills_30d);
$(element).find('#data_player_kills_7d').text(data.player_kills_7d);
$(element).find('#data_player_deaths_total').text(data.player_deaths_total);
$(element).find('#data_player_deaths_30d').text(data.player_deaths_30d);
$(element).find('#data_player_deaths_7d').text(data.player_deaths_7d);
$(element).find('#data_player_kdr_avg').text(data.player_kdr_avg);
$(element).find('#data_player_kdr_avg_30d').text(data.player_kdr_avg_30d);
$(element).find('#data_player_kdr_avg_7d').text(data.player_kdr_avg_7d);
$(element).find('#data_mob_kills_total').text(data.mob_kills_total);
$(element).find('#data_mob_kills_30d').text(data.mob_kills_30d);
@ -224,6 +224,10 @@ function loadPvPPvEValues(json, error) {
$(element).find('#data_mob_deaths_30d').text(data.mob_deaths_30d);
$(element).find('#data_mob_deaths_7d').text(data.mob_deaths_7d);
$(element).find('#data_mob_kdr_total').text(data.mob_kdr_total);
$(element).find('#data_mob_kdr_30d').text(data.mob_kdr_30d);
$(element).find('#data_mob_kdr_7d').text(data.mob_kdr_7d);
$(element).find('#data_deaths_total').text(data.deaths_total);
$(element).find('#data_deaths_30d').text(data.deaths_30d);
$(element).find('#data_deaths_7d').text(data.deaths_7d);
@ -235,7 +239,6 @@ function loadPvPPvEValues(json, error) {
$(element).find('#data_weapon_1st').text(data.weapon_1st);
$(element).find('#data_weapon_2nd').text(data.weapon_2nd);
$(element).find('#data_weapon_3rd').text(data.weapon_3rd);
$(element).find('#data_rage_quits').text(data.rage_quits)
}
/* This function loads Playerbase Overview tab */

View File

@ -600,20 +600,27 @@
<th>Last 7 days</th>
</thead>
<tbody>
<tr>
<td><b><i class="col-red fa fa-fw fa-crosshairs"></i></b> Average KDR / Player
</td>
<td id="data_player_kdr_avg"></td>
<td id="data_player_kdr_avg_30d"></td>
<td id="data_player_kdr_avg_7d"></td>
</tr>
<tr>
<td><i class="col-red fa fa-fw fa-crosshairs"></i> Player Kills</td>
<td id="data_player_kills_total"></td>
<td id="data_player_kills_30d"></td>
<td id="data_player_kills_7d"></td>
</tr>
<tr>
<td><i class="col-red fa fa-fw fa-skull"></i> Player Caused Deaths</td>
<td id="data_player_deaths_total"></td>
<td id="data_player_deaths_30d"></td>
<td id="data_player_deaths_7d"></td>
</tr>
</tbody>
<tbody>
<tr>
<td><b><i class="col-green fa fa-fw fa-crosshairs"></i></b> Average Mob KDR</td>
<td id="data_mob_kdr_total"></td>
<td id="data_mob_kdr_30d"></td>
<td id="data_mob_kdr_7d"></td>
</tr>
<tr>
<td><i class="col-green fa fa-fw fa-crosshairs"></i> Mob Kills</td>
<td id="data_mob_kills_total"></td>
@ -653,8 +660,6 @@
<span class="float-right"><b id="data_weapon_2nd"></b></span></p>
<p><i class="col-brown fa fa-fw fa-khanda"></i> 3rd PvP Weapon
<span class="float-right"><b id="data_weapon_3rd"></b></span></p>
<p><i class="col-red fa fa-fw fa-skull"></i> Rage Quits
<span class="float-right"><b id="data_rage_quits"></b></span></p>
</div>
</div>
</div>
@ -1411,33 +1416,7 @@
jsonRequest("../v1/serverOverview?serverName=${serverName}", loadServerOverviewValues);
jsonRequest("../v1/onlineOverview?serverName=${serverName}", loadOnlineActivityOverviewValues);
jsonRequest("../v1/sessionsOverview?serverName=${serverName}", loadSessionValues);
loadPvPPvEValues(
{
numbers: {
player_kills_total: 342,
player_kills_30d: 234,
player_kills_7d: 34,
player_deaths_total: 40,
player_deaths_30d: 34,
player_deaths_7d: 32,
mob_kills_total: 1232,
mob_kills_30d: 332,
mob_kills_7d: 32,
mob_deaths_total: 34,
mob_deaths_30d: 11,
mob_deaths_7d: 5,
deaths_total: 74,
deaths_30d: 44,
deaths_7d: 39
},
insights: {
weapon_1st: 'Diamond Sword',
weapon_2nd: 'Diamond Axe',
weapon_3rd: 'Iron Sword',
rage_quits: 4
}
}, null
);
jsonRequest("../v1/playerVersus?serverName=${serverName}", loadPvPPvEValues);
loadPlayerbaseOverviewValues(
{
trends: {

View File

@ -48,6 +48,17 @@ Parameter|Expected value|Description
`serverName` | Name of a Plan server | Used for identifying Plan server that the data should be about
`serverUUID` | UUID of a Plan server | Used for identifying Plan server that the data should be about
### `GET /v1/playerVersus`
Obtain data for PvP & PvE tab.
Required parameters: `serverName` or `serverUUID`
Parameter|Expected value|Description
--|--|--
`serverName` | Name of a Plan server | Used for identifying Plan server that the data should be about
`serverUUID` | UUID of a Plan server | Used for identifying Plan server that the data should be about
### `GET /v1/players`
Obtain data for `/server` player list.