Skip to content

Commit

Permalink
Add full support for Counter-Strike 2
Browse files Browse the repository at this point in the history
  • Loading branch information
Vauff committed Nov 16, 2023
1 parent 07a4894 commit 1680dc7
Show file tree
Hide file tree
Showing 9 changed files with 134 additions and 106 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<artifactId>maunz-discord</artifactId>
<name>Maunz</name>
<description>A multi-purpose Discord bot with a focus on Source server tracking</description>
<version>r56</version>
<version>r57</version>
<url>https://github.com/Vauff/Maunz-Discord</url>
<build>
<finalName>Maunz-Discord</finalName>
Expand Down
4 changes: 2 additions & 2 deletions src/com/vauff/maunzdiscord/commands/Map.java
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ private void runCmd(DeferrableInteractionEvent event, User user, Document doc, b
return;
}

String url = MapImages.getMapImageURL(doc.getString("lastMap"), serverDoc.getInteger("appId"));
String url = MapImages.getMapImageURL(doc.getString("lastMap"), serverDoc.getString("appId"));
String ipPort = serverDoc.getString("ip") + ":" + serverDoc.getInteger("port");

EmbedCreateSpec embed = EmbedCreateSpec.builder()
Expand Down Expand Up @@ -195,7 +195,7 @@ private void runCmd(DeferrableInteractionEvent event, User user, Document doc, b

if (!formattedMap.equals(""))
{
String url = MapImages.getMapImageURL(formattedMap, serverDoc.getInteger("appId"));
String url = MapImages.getMapImageURL(formattedMap, serverDoc.getString("appId"));
String lastPlayed = "";
String firstPlayed = "";

Expand Down
6 changes: 6 additions & 0 deletions src/com/vauff/maunzdiscord/commands/Players.java
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@ private void runCmd(DeferrableInteractionEvent event, User user, Document doc)

int numberOfPlayers = serverDoc.getList("players", String.class).size();

if (numberOfPlayers < 2 && serverDoc.getString("appId").equals("730_cs2"))
{
Util.editReply(event, "Players Online: **" + serverDoc.getString("playerCount") + "**\n\n**Note:** Counter-Strike 2 servers do not currently support querying player information");
return;
}

if (numberOfPlayers == 0)
{
Util.editReply(event, "There are currently no players online!");
Expand Down
2 changes: 1 addition & 1 deletion src/com/vauff/maunzdiscord/commands/Servers.java
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ private ObjectId getOrCreateServer(String ip, int port)
return id;
}

Document server = new Document("enabled", true).append("ip", ip).append("port", port).append("appId", 0).append("name", "N/A").append("map", "N/A").append("timestamp", 0L).append("playerCount", "0/0").append("players", new ArrayList())
Document server = new Document("enabled", true).append("ip", ip).append("port", port).append("appId", "0").append("name", "N/A").append("map", "N/A").append("timestamp", 0L).append("playerCount", "0/0").append("players", new ArrayList())
.append("downtimeTimer", 0).append("failedConnectionsThreshold", 3).append("mapDatabase", new ArrayList());

return Main.mongoDatabase.getCollection("servers").insertOne(server).getInsertedId().asObjectId().getValue();
Expand Down
2 changes: 1 addition & 1 deletion src/com/vauff/maunzdiscord/core/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public class Main
{
public static GatewayDiscordClient gateway;
public static MongoDatabase mongoDatabase;
public static String version = "r56";
public static String version = "r57";
public static Config cfg;

/**
Expand Down
9 changes: 4 additions & 5 deletions src/com/vauff/maunzdiscord/servertracking/MapImageTimer.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,16 +64,15 @@ public class MapImageTimer

Logger.log.debug("Map image API updated, rebuilding image list and clearing caches");

for (String key : response.keySet())
for (String appId : response.keySet())
{
if (!NumberUtils.isCreatable(key))
if (appId.equals("lastUpdated"))
continue;

ArrayList<String> maps = new ArrayList<>();
int appId = Integer.parseInt(key);

for (int i = 0; i < response.getJSONArray(key).length(); i++)
maps.add(response.getJSONArray(key).getString(i));
for (int i = 0; i < response.getJSONArray(appId).length(); i++)
maps.add(response.getJSONArray(appId).getString(i));

MapImages.mapImages.put(appId, maps);
MapImages.mapImageLookupCache.put(appId, new HashMap<>());
Expand Down
180 changes: 91 additions & 89 deletions src/com/vauff/maunzdiscord/servertracking/MapImages.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ public class MapImages
/**
* Holds the latest image lists pulled from vauff.com
*/
public static HashMap<Integer, ArrayList<String>> mapImages = new HashMap<>();
public static HashMap<String, ArrayList<String>> mapImages = new HashMap<>();

/**
* Cached lookup results from Util#getMapImageURL
*/
public static HashMap<Integer, HashMap<String, String>> mapImageLookupCache = new HashMap<>();
public static HashMap<String, HashMap<String, String>> mapImageLookupCache = new HashMap<>();

/**
* Cached colour results from Util#averageColourFromURL
Expand All @@ -38,7 +38,7 @@ public class MapImages
* @param appId App ID of the game
* @return Image URL for the map, or "" on failure
*/
public static String getMapImageURL(String map, int appId)
public static String getMapImageURL(String map, String appId)
{
// Force lower case since GameTracker does, and for an accurate levenshtein distance
String mapLower = map.toLowerCase();
Expand Down Expand Up @@ -88,7 +88,7 @@ public static Color getMapImageColour(String url) throws Exception
* @param appId App ID of the game
* @return Image URL for the map, or "" on failure
*/
private static String getVauffMapImageURL(String map, int appId)
private static String getVauffMapImageURL(String map, String appId)
{
// As we accomodate for mapCharacterLimit, all image map names at vauff.com should never exceed 31 characters
String trimmedMap = StringUtils.substring(map, 0, 31);
Expand Down Expand Up @@ -124,94 +124,96 @@ private static String getVauffMapImageURL(String map, int appId)
* @param appId App ID of the game
* @return GameTracker's directory name for the given game
*/
private static String appIdToGameTrackerName(int appId)
private static String appIdToGameTrackerName(String appId)
{
return switch (appId)
{
case 10 -> "cs";
case 20 -> "tfc";
case 30 -> "dod";
case 70 -> "hl";
case 80 -> "czero";
case 240 -> "css";
case 300 -> "dods";
case 320 -> "hl2dm";
case 440 -> "tf2";
case 500 -> "l4d";
case 550 -> "left4dead2";
case 570 -> "dota2";
case 630 -> "alienswarm";
case 730 -> "csgo";
case 1200 -> "ror";
case 1250 -> "killingfloor";
case 1280 -> "rordh";
case 2200 -> "q3";
case 2210 -> "q4";
case 2310 -> "qw";
case 2320 -> "q2";
case 2620 -> "cod";
case 2630 -> "cod2";
case 2640 -> "uo";
case 4000 -> "garrysmod";
case 4920 -> "ns2";
case 6020 -> "swjk";
case 6060 -> "swbf2";
case 7940 -> "cod4";
case 9010 -> "wolf";
case 9050 -> "doom3";
case 9460 -> "ffow";
case 10000 -> "etqw";
case 10090 -> "codww";
case 13140 -> "aa3";
case 13210 -> "ut3";
case 13230 -> "ut2k4";
case 13240 -> "ut";
case 17300 -> "crysis";
case 17330 -> "warhead";
case 17500 -> "hl2zp";
case 17700 -> "ins";
case 21090 -> "fear";
case 22350 -> "brink";
case 24960 -> "bc2";
case 33900 -> "arma2";
case 35450 -> "ro2";
case 42700 -> "blackops";
case 47790 -> "moh";
case 55100 -> "homefront";
case 63200 -> "mnc";
case 63380 -> "sniperelite2";
case 65780 -> "arma";
case 96300 -> "ravaged";
case 107410 -> "arma3";
case 108800 -> "crysis2";
case 115300 -> "mw3";
case 203290 -> "aapg";
case 211820 -> "starbound";
case 214630 -> "blackopsmac";
case 221100 -> "dayz";
case 222880 -> "insurgency2014";
case 224580 -> "dayzmod";
case 232090 -> "kf2";
case 238430 -> "contagion";
case 244850 -> "spaceengi";
case 251570 -> "7daystodie";
case 252490 -> "rust";
case 253530 -> "ff";
case 259080 -> "jc2";
case 282440 -> "ql";
case 290080 -> "lifyo";
case 311210 -> "codbo3";
case 346110 -> "arkse";
case 393420 -> "hurtworld";
case 440900 -> "conan";
case 489940 -> "battalion1944";
case 529180 -> "dnl";
case 581320 -> "ins_sandstorm";
case 659280 -> "urbanterror";
case 1238820 -> "bf3";
case 1238860 -> "bf4";
case 1238880 -> "bfhl";
case 1873030 -> "et";
case "10" -> "cs";
case "20" -> "tfc";
case "30" -> "dod";
case "70" -> "hl";
case "80" -> "czero";
case "240" -> "css";
case "300" -> "dods";
case "320" -> "hl2dm";
case "440" -> "tf2";
case "500" -> "l4d";
case "550" -> "left4dead2";
case "570" -> "dota2";
case "630" -> "alienswarm";
case "730_csgo" -> "csgo";
// TODO: Update this if GameTracker ever gets CS2 support
case "730_cs2" -> "csgo";
case "1200" -> "ror";
case "1250" -> "killingfloor";
case "1280" -> "rordh";
case "2200" -> "q3";
case "2210" -> "q4";
case "2310" -> "qw";
case "2320" -> "q2";
case "2620" -> "cod";
case "2630" -> "cod2";
case "2640" -> "uo";
case "4000" -> "garrysmod";
case "4920" -> "ns2";
case "6020" -> "swjk";
case "6060" -> "swbf2";
case "7940" -> "cod4";
case "9010" -> "wolf";
case "9050" -> "doom3";
case "9460" -> "ffow";
case "10000" -> "etqw";
case "10090" -> "codww";
case "13140" -> "aa3";
case "13210" -> "ut3";
case "13230" -> "ut2k4";
case "13240" -> "ut";
case "17300" -> "crysis";
case "17330" -> "warhead";
case "17500" -> "hl2zp";
case "17700" -> "ins";
case "21090" -> "fear";
case "22350" -> "brink";
case "24960" -> "bc2";
case "33900" -> "arma2";
case "35450" -> "ro2";
case "42700" -> "blackops";
case "47790" -> "moh";
case "55100" -> "homefront";
case "63200" -> "mnc";
case "63380" -> "sniperelite2";
case "65780" -> "arma";
case "96300" -> "ravaged";
case "107410" -> "arma3";
case "108800" -> "crysis2";
case "115300" -> "mw3";
case "203290" -> "aapg";
case "211820" -> "starbound";
case "214630" -> "blackopsmac";
case "221100" -> "dayz";
case "222880" -> "insurgency2014";
case "224580" -> "dayzmod";
case "232090" -> "kf2";
case "238430" -> "contagion";
case "244850" -> "spaceengi";
case "251570" -> "7daystodie";
case "252490" -> "rust";
case "253530" -> "ff";
case "259080" -> "jc2";
case "282440" -> "ql";
case "290080" -> "lifyo";
case "311210" -> "codbo3";
case "346110" -> "arkse";
case "393420" -> "hurtworld";
case "440900" -> "conan";
case "489940" -> "battalion1944";
case "529180" -> "dnl";
case "581320" -> "ins_sandstorm";
case "659280" -> "urbanterror";
case "1238820" -> "bf3";
case "1238860" -> "bf4";
case "1238880" -> "bfhl";
case "1873030" -> "et";
default -> "";
};
}
Expand Down
33 changes: 27 additions & 6 deletions src/com/vauff/maunzdiscord/servertracking/ServerRequestThread.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,11 @@ public void run()
serverInfoSuccess = true;
}

// TODO: Remove this eventually when most CS:GO servers die, issue is not present in CS2 and isn't worth keeping for a few servers
// CS:GO servers by default use host_info_show 1 which uses a game-specific A2S_INFO implementation, only host_info_show 2 uses SteamWorks
// Unfortunately this implementation is incapable of providing a correct player count during a map change (returns 0), so we work around this by double-checking "empty" CS:GO servers are actually empty a little while after
// See https://github.com/perilouswithadollarsign/cstrike15_src/blob/master/engine/baseserver.cpp#L1261, GetNumPlayers() uses m_pUserInfoTable which is emptied during a map change
if (doc.getInteger("appId") == 730 && server.getServerInfo().containsKey("numberOfPlayers") && !Objects.isNull(server.getServerInfo().get("numberOfPlayers")) && ((Byte) server.getServerInfo().get("numberOfPlayers")).intValue() == 0 && !retriedForCsgoPlayerCount)
if (doc.getString("appId").equals("730_csgo") && server.getServerInfo().containsKey("numberOfPlayers") && !Objects.isNull(server.getServerInfo().get("numberOfPlayers")) && ((Byte) server.getServerInfo().get("numberOfPlayers")).intValue() == 0 && !retriedForCsgoPlayerCount)
{
Thread.sleep(5000);
serverInfoSuccess = false;
Expand Down Expand Up @@ -131,7 +132,7 @@ public void run()

HashMap<String, Object> serverInfo = server.getServerInfo();
long timestamp = 0;
int appId = 0;
String appId = "0";
String map = "";
String name = "N/A";
int currentPlayers = 0;
Expand All @@ -149,11 +150,31 @@ public void run()

// 24-bit app id within 64-bit game id, may not be available
if (serverInfo.containsKey("gameId") && !Objects.isNull(serverInfo.get("gameId")))
appId = (int) (((long) serverInfo.get("gameId")) & (1L << 24) - 1L);

appId = String.valueOf((int) (((long) serverInfo.get("gameId")) & (1L << 24) - 1L));
// 16-bit app id, possibly truncated but (theoretically) always available
else if (serverInfo.containsKey("appId") && !Objects.isNull(serverInfo.get("appId")))
appId = (short) serverInfo.get("appId");
appId = String.valueOf((short) serverInfo.get("appId"));

// Special handling for CS:GO/CS2, thanks for two games on the same app id, Valve!
if (appId.equals("730"))
{
if (serverInfo.containsKey("gameVersion") && !Objects.isNull(serverInfo.get("gameVersion")))
{
String version = serverInfo.get("gameVersion").toString();

// Strip periods, take first three numbers only e.g. "1.38.8.1" > 138
int majorVersion = Integer.parseInt(version.replace(".", "").substring(0, 3));

if (majorVersion >= 139)
appId = "730_cs2";
else if (majorVersion <= 138)
appId = "730_csgo";
}
else
{
appId = "0";
}
}

if (serverInfo.containsKey("serverName") && !Objects.isNull(serverInfo.get("serverName")))
name = serverInfo.get("serverName").toString();
Expand Down Expand Up @@ -201,7 +222,7 @@ else if (serverInfo.containsKey("appId") && !Objects.isNull(serverInfo.get("appI
}
}

if (appId != 0 && appId != doc.getInteger("appId"))
if (!appId.equals("0") && !appId.equals(doc.getString("appId")))
Main.mongoDatabase.getCollection("servers").updateOne(eq("_id", id), new Document("$set", new Document("appId", appId)));

if (!playerCount.equals("") && !playerCount.equals(doc.getString("playerCount")))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public void run()

if (!map.equals("") && !doc.getString("lastMap").equalsIgnoreCase(map))
{
String url = MapImages.getMapImageURL(map, serverDoc.getInteger("appId"));
String url = MapImages.getMapImageURL(map, serverDoc.getString("appId"));
String ipPort = serverDoc.getString("ip") + ":" + serverDoc.getInteger("port");

EmbedCreateSpec embed = EmbedCreateSpec.builder()
Expand Down

0 comments on commit 1680dc7

Please sign in to comment.