Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,13 @@ You can **import** your own **tag ignore list** by doing, type `/tagignore impor

To **skin denick** type `/skindenick <username>`

To use the **number denicker** add your Aurora API key
To use the **number denicker**, select your provider in **Settings > Number Denicker** and add the matching API key

- You can obtain one [here](https://discord.com/oauth2/authorize?client_id=1244205279697174539)
- After setup, denicking happens automatically during games, but you can also manually run: `/denick <finals | beds> <number>`
- After setup, denicking happens automatically during games, but you can also manually run `/denick`.
- `/denick` uses the provider selected in **Settings > Number Denicker**:
- **Aurora**: `/denick <finals | beds> <number>`
- **Frosty**: `/denick <finals_count> <beds_count>`

## Known issues

Expand Down
14 changes: 12 additions & 2 deletions src/main/java/com/roxiun/mellow/Mellow.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.roxiun.mellow.api.aurora.AuroraApi;
import com.roxiun.mellow.api.aurora.AuroraPingService;
import com.roxiun.mellow.api.aurora.AuroraWinstreakService;
import com.roxiun.mellow.api.frosty.FrostyApi;
import com.roxiun.mellow.api.hypixel.HypixelFeatures;
import com.roxiun.mellow.api.luna.LunaPingService;
import com.roxiun.mellow.api.mojang.MojangApi;
Expand Down Expand Up @@ -69,6 +70,7 @@ public class Mellow {
public static AuroraPingService auroraPingService;
public static AuroraWinstreakService auroraWinstreakService;
public static AuroraApi auroraApi;
public static FrostyApi frostyApi;
public static LunaPingService lunaPingService;
public static SeraphClientCacheService seraphClientCacheService;
public static SeraphPingService seraphPingService;
Expand Down Expand Up @@ -110,6 +112,7 @@ public void init(FMLInitializationEvent event) {
seraphApi = new SeraphApi(mojangApi);
seraphClientCacheService = new SeraphClientCacheService(seraphApi, config);
auroraApi = new AuroraApi();
frostyApi = new FrostyApi();

playerCache = new PlayerCache(
mojangApi,
Expand All @@ -135,7 +138,8 @@ public void init(FMLInitializationEvent event) {
NumberDenicker numberDenicker = new NumberDenicker(
config,
nickUtils,
auroraApi
auroraApi,
frostyApi
);
PregameStats pregameStats = new PregameStats(
playerCache,
Expand Down Expand Up @@ -242,7 +246,13 @@ public void run() {
new RefreshCommand(inGameTabStatsSyncService)
);
ClientCommandHandler.instance.registerCommand(
new DenickCommand(config, auroraApi)
new DenickCommand(config, auroraApi, frostyApi)
);
ClientCommandHandler.instance.registerCommand(
new AuroraDenickCommand(config, auroraApi)
);
ClientCommandHandler.instance.registerCommand(
new FrostyDenickCommand(config, frostyApi)
);
ClientCommandHandler.instance.registerCommand(
new SkinDenickCommand(playerCache)
Expand Down
112 changes: 112 additions & 0 deletions src/main/java/com/roxiun/mellow/api/frosty/FrostyApi.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package com.roxiun.mellow.api.frosty;

import com.google.gson.Gson;
import com.roxiun.mellow.util.cache.TimedValueCache;
import java.io.IOException;
import java.util.Locale;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;

public class FrostyApi {

private static final long QUERY_CACHE_TTL_MS = 60_000L;
private static final String BASE_URL =
"https://api.sukie.net/v1/bedwars/cosmetics";

private final OkHttpClient client;
private final Gson gson;
private final TimedValueCache<String, String> queryCache =
new TimedValueCache<>(QUERY_CACHE_TTL_MS);

public FrostyApi() {
this(new OkHttpClient(), new Gson());
}

FrostyApi(OkHttpClient client) {
this(client, new Gson());
}

FrostyApi(OkHttpClient client, Gson gson) {
this.client = client == null ? new OkHttpClient() : client;
this.gson = gson == null ? new Gson() : gson;
}

public FrostyReponse queryStats(
int finalKills,
int bedsBroken,
String apiKey
) throws IOException {
return queryCosmetics(finalKills, bedsBroken, apiKey);
}

public FrostyReponse queryCosmetics(
int finalKills,
int bedsBroken,
String apiKey
) throws IOException {
if (apiKey == null || apiKey.isEmpty()) {
return null;
}

if (finalKills == 0 && bedsBroken == 0) {
return null;
}

String cacheKey = buildCacheKey(finalKills, bedsBroken, apiKey);
if (queryCache.containsFresh(cacheKey)) {
return parseResponse(queryCache.get(cacheKey));
}

String finalsKillsParam = finalKills == 0 ? "" : "&final_kills=" + finalKills;
String bedsBrokenParam = bedsBroken == 0 ? "" : "&beds_broken=" + bedsBroken;
String url = BASE_URL + "?key=" + apiKey + finalsKillsParam + bedsBrokenParam + "&rank=mvp%2B%2B";

Request request = new Request.Builder()
.url(url)
.header("User-Agent", "Mellow/4.1.0")
.build();

try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) {
System.err.println("Frosty API request failed: " + response);
queryCache.put(cacheKey, null);
return null;
}

ResponseBody body = response.body();
if (body == null) {
queryCache.put(cacheKey, null);
return null;
}

String payload = body.string();
queryCache.put(cacheKey, payload);
return parseResponse(payload);
}
}

public void clearCache() {
queryCache.clear();
}

private FrostyReponse parseResponse(String payload) {
return payload == null ? null : gson.fromJson(payload, FrostyReponse.class);
}

private String buildCacheKey(int finalKills, int bedsBroken, String apiKey) {
return (
finalKills +
"|" +
bedsBroken +
"|" +
safe(apiKey).toLowerCase(Locale.ROOT)
);
}

private String safe(String value) {
return value == null ? "" : value.trim();
}
}

101 changes: 101 additions & 0 deletions src/main/java/com/roxiun/mellow/api/frosty/FrostyReponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package com.roxiun.mellow.api.frosty;

import com.google.gson.annotations.SerializedName;
import java.util.List;

public class FrostyReponse {

@SerializedName("success")
public boolean success;

@SerializedName("data")
public List<PlayerResult> data;

public static class PlayerResult {

@SerializedName("username")
public String username;

@SerializedName("uuid")
public String uuid;

@SerializedName("game_rank")
public String gameRank;

@SerializedName("rank_color")
public String rankColor;

@SerializedName("plus_color")
public String plusColor;

@SerializedName("network_level")
public long networkLevel;

@SerializedName("last_online")
public String lastOnline;

@SerializedName("bedwars_index")
public long bedwarsIndex;

@SerializedName("bedwars_level")
public long bedwarsLevel;

@SerializedName("total_final_kills")
public long totalFinalKills;

@SerializedName("total_final_deaths")
public long totalFinalDeaths;

@SerializedName("total_beds_broken")
public long totalBedsBroken;

@SerializedName("total_beds_lost")
public long totalBedsLost;

@SerializedName("total_wins")
public long totalWins;

@SerializedName("total_losses")
public long totalLosses;

@SerializedName("island_topper")
public String islandTopper;

@SerializedName("victory_dance")
public String victoryDance;

@SerializedName("kill_effect")
public String killEffect;

@SerializedName("projectile_trail")
public String projectileTrail;

@SerializedName("kill_message")
public String killMessage;

@SerializedName("npc_skin")
public String npcSkin;

@SerializedName("death_cry")
public String deathCry;

@SerializedName("spray")
public String spray;

@SerializedName("bed_destroy")
public String bedDestroy;

@SerializedName("glyph")
public String glyph;

@SerializedName("wood_type")
public String woodType;

@SerializedName("starting_weapon")
public String startingWeapon;

@SerializedName("figurine")
public String figurine;
}
}

Loading
Loading