Hiscore feature expansion (#152)
* Add remaining Hiscore parameters to HiscoreSkill * Add remaining Hiscore parameters to HiscoreResult * Add remaining Hiscore parameters to HiscoreResultBuilder * Add new Hiscore panel icons (from offical Hiscore website, so they don't match very well) and subpanel for Clue Scrolls, Bounty Hunter - Hunter, Bounty Hunter - Rogue, and Last Man Standing * Add logic to catch unranked hiscores and display them properly. Not currently checking for combat level calculations, but other cases should be covered. * Make HiscoreService and HiscoreClient aware of different hiscore endpoints * Add Spring Editor to convert path variable String to enum, add pretty versions of HiscoreEndpoint names, add new icons for endpoint selection * Fix HiscoreEndpoint.valueof failing silently and preventing lookup, update HiscoreService tests, add Hiscore endpoint selection buttons to HiscorePanel * Replace HiscorePanel skill icons with smaller versions from the official hiscore website * Fix details listing rank instead of experience * Fix details listing rank instead of experience, fix skill panels not being cleared when selecting a different hiscore category, make HiscoreService respond 404 when a Hiscore entry is not found instead of 500. * Fix skill panels not being cleared when selecting a different hiscore category, make HiscoreService respond 404 when a Hiscore entry is not found instead of 500. * Revert changing RuneliteAPI base URL, those changes should not have been committed (local testing only) * Add ClueScrollAll and ClueScrollMaster to HiscoreService tests. * Style cleanup and relocate NotFoundException to http-service package * Use relative path for small skill icons * Move Jagex Hiscore urls from HiscoreService to HiscoreEndpoint * Create new util package in http-service for common exceptions and Spring converters, clean up HiscoreService by streamlining error handling and removing methods for old unit test * Change HiscoreService unit test to use new HiscoreTestService subclass which handles setting the test URL * Change HiscoreEndpoint hiscoreUrls to HttpUrl instead of String * Cleanup formatting, remove unused http-service exception * http-api: cleanup HiscoreEndpoint
@@ -40,10 +40,11 @@ public class HiscoreClient
|
||||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(HiscoreClient.class);
|
||||
|
||||
public HiscoreResult lookup(String username) throws IOException
|
||||
public HiscoreResult lookup(String username, HiscoreEndpoint endpoint) throws IOException
|
||||
{
|
||||
HttpUrl.Builder builder = RuneliteAPI.getApiBase().newBuilder()
|
||||
.addPathSegment("hiscore")
|
||||
.addPathSegment(endpoint.name().toLowerCase())
|
||||
.addQueryParameter("username", username);
|
||||
|
||||
HttpUrl url = builder.build();
|
||||
@@ -67,10 +68,16 @@ public class HiscoreClient
|
||||
}
|
||||
}
|
||||
|
||||
public SingleHiscoreSkillResult lookup(String username, HiscoreSkill skill) throws IOException
|
||||
public HiscoreResult lookup(String username) throws IOException
|
||||
{
|
||||
return lookup(username, HiscoreEndpoint.NORMAL);
|
||||
}
|
||||
|
||||
public SingleHiscoreSkillResult lookup(String username, HiscoreSkill skill, HiscoreEndpoint endpoint) throws IOException
|
||||
{
|
||||
HttpUrl.Builder builder = RuneliteAPI.getApiBase().newBuilder()
|
||||
.addPathSegment("hiscore")
|
||||
.addPathSegment(endpoint.name())
|
||||
.addPathSegment(skill.toString().toLowerCase())
|
||||
.addQueryParameter("username", username);
|
||||
|
||||
@@ -94,4 +101,9 @@ public class HiscoreClient
|
||||
throw new IOException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public SingleHiscoreSkillResult lookup(String username, HiscoreSkill skill) throws IOException
|
||||
{
|
||||
return lookup(username, skill, HiscoreEndpoint.NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package net.runelite.http.api.hiscore;
|
||||
|
||||
import okhttp3.HttpUrl;
|
||||
|
||||
public enum HiscoreEndpoint
|
||||
{
|
||||
NORMAL("Normal", "http://services.runescape.com/m=hiscore_oldschool/index_lite.ws"),
|
||||
IRONMAN("Ironman", "http://services.runescape.com/m=hiscore_oldschool_ironman/index_lite.ws"),
|
||||
HARDCORE_IRONMAN("Hardcore Ironman", "http://services.runescape.com/m=hiscore_oldschool_hardcore_ironman/index_lite.ws"),
|
||||
ULTIMATE_IRONMAN("Ultimate Ironman", "http://services.runescape.com/m=hiscore_oldschool_ultimate/index_lite.ws"),
|
||||
DEADMAN("Deadman", "http://services.runescape.com/m=hiscore_oldschool_deadman/index_lite.ws"),
|
||||
SEASONAL_DEADMAN("Seasonal Deadman", "http://services.runescape.com/m=hiscore_oldschool_seasonal/index_lite.ws");
|
||||
|
||||
private final String name;
|
||||
private final HttpUrl hiscoreURL;
|
||||
|
||||
HiscoreEndpoint(String name, String hiscoreURL)
|
||||
{
|
||||
this.name = name;
|
||||
this.hiscoreURL = HttpUrl.parse(hiscoreURL);
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public HttpUrl getHiscoreURL()
|
||||
{
|
||||
return hiscoreURL;
|
||||
}
|
||||
}
|
||||
@@ -53,6 +53,15 @@ public class HiscoreResult
|
||||
private Skill runecraft;
|
||||
private Skill hunter;
|
||||
private Skill construction;
|
||||
private Skill clueScrollEasy;
|
||||
private Skill clueScrollMedium;
|
||||
private Skill clueScrollAll;
|
||||
private Skill bountyHunterRogue;
|
||||
private Skill bountyHunterHunter;
|
||||
private Skill clueScrollHard;
|
||||
private Skill lastManStanding;
|
||||
private Skill clueScrollElite;
|
||||
private Skill clueScrollMaster;
|
||||
|
||||
public String getPlayer()
|
||||
{
|
||||
@@ -304,6 +313,96 @@ public class HiscoreResult
|
||||
this.construction = construction;
|
||||
}
|
||||
|
||||
public Skill getClueScrollEasy()
|
||||
{
|
||||
return clueScrollEasy;
|
||||
}
|
||||
|
||||
public void setClueScrollEasy(Skill clueScrollEasy)
|
||||
{
|
||||
this.clueScrollEasy = clueScrollEasy;
|
||||
}
|
||||
|
||||
public Skill getClueScrollMedium()
|
||||
{
|
||||
return clueScrollMedium;
|
||||
}
|
||||
|
||||
public void setClueScrollMedium(Skill clueScrollMedium)
|
||||
{
|
||||
this.clueScrollMedium = clueScrollMedium;
|
||||
}
|
||||
|
||||
public Skill getClueScrollAll()
|
||||
{
|
||||
return clueScrollAll;
|
||||
}
|
||||
|
||||
public void setClueScrollAll(Skill clueScrollAll)
|
||||
{
|
||||
this.clueScrollAll = clueScrollAll;
|
||||
}
|
||||
|
||||
public Skill getBountyHunterRogue()
|
||||
{
|
||||
return bountyHunterRogue;
|
||||
}
|
||||
|
||||
public void setBountyHunterRogue(Skill bountyHunterRogue)
|
||||
{
|
||||
this.bountyHunterRogue = bountyHunterRogue;
|
||||
}
|
||||
|
||||
public Skill getBountyHunterHunter()
|
||||
{
|
||||
return bountyHunterHunter;
|
||||
}
|
||||
|
||||
public void setBountyHunterHunter(Skill bountyHunterHunter)
|
||||
{
|
||||
this.bountyHunterHunter = bountyHunterHunter;
|
||||
}
|
||||
|
||||
public Skill getClueScrollHard()
|
||||
{
|
||||
return clueScrollHard;
|
||||
}
|
||||
|
||||
public void setClueScrollHard(Skill clueScrollHard)
|
||||
{
|
||||
this.clueScrollHard = clueScrollHard;
|
||||
}
|
||||
|
||||
public Skill getLastManStanding()
|
||||
{
|
||||
return lastManStanding;
|
||||
}
|
||||
|
||||
public void setLastManStanding(Skill lastManStanding)
|
||||
{
|
||||
this.lastManStanding = lastManStanding;
|
||||
}
|
||||
|
||||
public Skill getClueScrollElite()
|
||||
{
|
||||
return clueScrollElite;
|
||||
}
|
||||
|
||||
public void setClueScrollElite(Skill clueScrollElite)
|
||||
{
|
||||
this.clueScrollElite = clueScrollElite;
|
||||
}
|
||||
|
||||
public Skill getClueScrollMaster()
|
||||
{
|
||||
return clueScrollMaster;
|
||||
}
|
||||
|
||||
public void setClueScrollMaster(Skill clueScrollMaster)
|
||||
{
|
||||
this.clueScrollMaster = clueScrollMaster;
|
||||
}
|
||||
|
||||
public Skill getSkill(HiscoreSkill skill)
|
||||
{
|
||||
switch (skill)
|
||||
@@ -356,9 +455,27 @@ public class HiscoreResult
|
||||
return getConstruction();
|
||||
case OVERALL:
|
||||
return getOverall();
|
||||
case CLUE_SCROLL_EASY:
|
||||
return getClueScrollEasy();
|
||||
case CLUE_SCROLL_MEDIUM:
|
||||
return getClueScrollMedium();
|
||||
case CLUE_SCROLL_ALL:
|
||||
return getClueScrollAll();
|
||||
case BOUNTY_HUNTER_ROGUE:
|
||||
return getBountyHunterRogue();
|
||||
case BOUNTY_HUNTER_HUNTER:
|
||||
return getBountyHunterHunter();
|
||||
case CLUE_SCROLL_HARD:
|
||||
return getClueScrollHard();
|
||||
case LAST_MAN_STANDING:
|
||||
return getLastManStanding();
|
||||
case CLUE_SCROLL_ELITE:
|
||||
return getClueScrollElite();
|
||||
case CLUE_SCROLL_MASTER:
|
||||
return getClueScrollMaster();
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Invalid skill");
|
||||
throw new IllegalArgumentException("Invalid hiscore item");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -390,6 +507,15 @@ public class HiscoreResult
|
||||
hash = 29 * hash + Objects.hashCode(this.runecraft);
|
||||
hash = 29 * hash + Objects.hashCode(this.hunter);
|
||||
hash = 29 * hash + Objects.hashCode(this.construction);
|
||||
hash = 29 * hash + Objects.hashCode(this.clueScrollEasy);
|
||||
hash = 29 * hash + Objects.hashCode(this.clueScrollMedium);
|
||||
hash = 29 * hash + Objects.hashCode(this.clueScrollAll);
|
||||
hash = 29 * hash + Objects.hashCode(this.bountyHunterRogue);
|
||||
hash = 29 * hash + Objects.hashCode(this.bountyHunterHunter);
|
||||
hash = 29 * hash + Objects.hashCode(this.clueScrollHard);
|
||||
hash = 29 * hash + Objects.hashCode(this.lastManStanding);
|
||||
hash = 29 * hash + Objects.hashCode(this.clueScrollElite);
|
||||
hash = 29 * hash + Objects.hashCode(this.clueScrollMaster);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@@ -509,12 +635,48 @@ public class HiscoreResult
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!Objects.equals(this.clueScrollEasy, other.clueScrollEasy))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!Objects.equals(this.clueScrollMedium, other.clueScrollMedium))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!Objects.equals(this.clueScrollAll, other.clueScrollAll))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!Objects.equals(this.bountyHunterRogue, other.bountyHunterRogue))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!Objects.equals(this.bountyHunterHunter, other.bountyHunterHunter))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!Objects.equals(this.clueScrollHard, other.clueScrollHard))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!Objects.equals(this.lastManStanding, other.lastManStanding))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!Objects.equals(this.clueScrollElite, other.clueScrollElite))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!Objects.equals(this.clueScrollMaster, other.clueScrollMaster))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "HiscoreResult{" + "player=" + player + ", overall=" + overall + ", attack=" + attack + ", defence=" + defence + ", strength=" + strength + ", hitpoints=" + hitpoints + ", ranged=" + ranged + ", prayer=" + prayer + ", magic=" + magic + ", cooking=" + cooking + ", woodcutting=" + woodcutting + ", fletching=" + fletching + ", fishing=" + fishing + ", firemaking=" + firemaking + ", crafting=" + crafting + ", smithing=" + smithing + ", mining=" + mining + ", herblore=" + herblore + ", agility=" + agility + ", thieving=" + thieving + ", slayer=" + slayer + ", farming=" + farming + ", runecraft=" + runecraft + ", hunter=" + hunter + ", construction=" + construction + '}';
|
||||
return "HiscoreResult{" + "player=" + player + ", overall=" + overall + ", attack=" + attack + ", defence=" + defence + ", strength=" + strength + ", hitpoints=" + hitpoints + ", ranged=" + ranged + ", prayer=" + prayer + ", magic=" + magic + ", cooking=" + cooking + ", woodcutting=" + woodcutting + ", fletching=" + fletching + ", fishing=" + fishing + ", firemaking=" + firemaking + ", crafting=" + crafting + ", smithing=" + smithing + ", mining=" + mining + ", herblore=" + herblore + ", agility=" + agility + ", thieving=" + thieving + ", slayer=" + slayer + ", farming=" + farming + ", runecraft=" + runecraft + ", hunter=" + hunter + ", construction=" + construction + ", clueScrollEasy=" + clueScrollEasy + ", clueScrollMedium=" + clueScrollMedium + ", clueScrollAll=" + clueScrollAll + ", bountyHunterRogue=" + bountyHunterRogue + ", bountyHunterHunter=" + bountyHunterHunter + ", clueScrollHard=" + clueScrollHard + ", lastManStanding=" + lastManStanding + ", clueScrollElite=" + clueScrollElite + ", clueScrollMaster=" + clueScrollMaster + '}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,16 @@ public enum HiscoreSkill
|
||||
FARMING("Farming"),
|
||||
RUNECRAFT("Runecraft"),
|
||||
HUNTER("Hunter"),
|
||||
CONSTRUCTION("Construction");
|
||||
CONSTRUCTION("Construction"),
|
||||
CLUE_SCROLL_EASY("Clue Scrolls (easy)"),
|
||||
CLUE_SCROLL_MEDIUM("Clue Scrolls (medium)"),
|
||||
CLUE_SCROLL_ALL("Clue Scrolls (all)"),
|
||||
BOUNTY_HUNTER_ROGUE("Bounty Hunter - Rogue"),
|
||||
BOUNTY_HUNTER_HUNTER("Bounty Hunter - Hunter"),
|
||||
CLUE_SCROLL_HARD("Clue Scrolls (hard)"),
|
||||
LAST_MAN_STANDING("Last Man Standing"),
|
||||
CLUE_SCROLL_ELITE("Clue Scrolls (elite)"),
|
||||
CLUE_SCROLL_MASTER("Clue Scrolls (master)");
|
||||
|
||||
private final String name;
|
||||
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.http.service;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.time.Instant;
|
||||
import org.sql2o.converters.Converter;
|
||||
import org.sql2o.converters.ConverterException;
|
||||
|
||||
public class InstantConverter implements Converter<Instant>
|
||||
{
|
||||
@Override
|
||||
public Instant convert(Object val) throws ConverterException
|
||||
{
|
||||
Timestamp ts = (Timestamp) val;
|
||||
return ts.toInstant();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object toDatabaseParam(Instant val)
|
||||
{
|
||||
return Timestamp.from(val);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -31,6 +31,8 @@ import javax.naming.Context;
|
||||
import javax.naming.InitialContext;
|
||||
import javax.naming.NamingException;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import net.runelite.http.service.util.InstantConverter;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
|
||||
@@ -55,6 +55,7 @@ import net.runelite.cache.fs.jagex.DataFileReadResult;
|
||||
import net.runelite.http.api.cache.Cache;
|
||||
import net.runelite.http.api.cache.CacheArchive;
|
||||
import net.runelite.http.api.cache.CacheIndex;
|
||||
import net.runelite.http.service.util.exception.NotFoundException;
|
||||
import net.runelite.http.service.cache.beans.ArchiveEntry;
|
||||
import net.runelite.http.service.cache.beans.CacheEntry;
|
||||
import net.runelite.http.service.cache.beans.FileEntry;
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.http.service.cache;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "Not found")
|
||||
public class NotFoundException extends RuntimeException
|
||||
{
|
||||
|
||||
}
|
||||
@@ -77,6 +77,15 @@ public class HiscoreResultBuilder
|
||||
hiscoreResult.setRunecraft(skills.get(21));
|
||||
hiscoreResult.setHunter(skills.get(22));
|
||||
hiscoreResult.setConstruction(skills.get(23));
|
||||
hiscoreResult.setClueScrollEasy(skills.get(24));
|
||||
hiscoreResult.setClueScrollMedium(skills.get(25));
|
||||
hiscoreResult.setClueScrollAll(skills.get(26));
|
||||
hiscoreResult.setBountyHunterRogue(skills.get(27));
|
||||
hiscoreResult.setBountyHunterHunter(skills.get(28));
|
||||
hiscoreResult.setClueScrollHard(skills.get(29));
|
||||
hiscoreResult.setLastManStanding(skills.get(30));
|
||||
hiscoreResult.setClueScrollElite(skills.get(31));
|
||||
hiscoreResult.setClueScrollMaster(skills.get(32));
|
||||
return hiscoreResult;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,10 +26,10 @@ package net.runelite.http.service.hiscore;
|
||||
|
||||
import java.io.IOException;
|
||||
import net.runelite.http.api.RuneliteAPI;
|
||||
import net.runelite.http.api.hiscore.HiscoreResult;
|
||||
import net.runelite.http.api.hiscore.SingleHiscoreSkillResult;
|
||||
import net.runelite.http.api.hiscore.Skill;
|
||||
import net.runelite.http.api.hiscore.HiscoreSkill;
|
||||
import net.runelite.http.api.hiscore.*;
|
||||
import net.runelite.http.service.util.HiscoreEndpointEditor;
|
||||
import net.runelite.http.service.util.exception.InternalServerErrorException;
|
||||
import net.runelite.http.service.util.exception.NotFoundException;
|
||||
import okhttp3.HttpUrl;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
@@ -39,10 +39,9 @@ import org.apache.commons.csv.CSVParser;
|
||||
import org.apache.commons.csv.CSVRecord;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/hiscore")
|
||||
@@ -50,23 +49,36 @@ public class HiscoreService
|
||||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(HiscoreService.class);
|
||||
|
||||
private static final HttpUrl RUNESCAPE_HISCORE_SERVICE = HttpUrl.parse("http://services.runescape.com/m=hiscore_oldschool/index_lite.ws");
|
||||
|
||||
private HttpUrl url = RUNESCAPE_HISCORE_SERVICE;
|
||||
|
||||
private HiscoreResultBuilder lookupUsername(String username) throws IOException
|
||||
HiscoreResultBuilder lookupUsername(String username, HiscoreEndpoint endpoint) throws IOException
|
||||
{
|
||||
HttpUrl hiscoreUrl = url.newBuilder()
|
||||
.addQueryParameter("player", username)
|
||||
.build();
|
||||
return lookupUsername(username, endpoint.getHiscoreURL());
|
||||
}
|
||||
|
||||
logger.info("Built URL {}", hiscoreUrl);
|
||||
HiscoreResultBuilder lookupUsername(String username, HttpUrl hiscoreUrl) throws IOException
|
||||
{
|
||||
HttpUrl url = hiscoreUrl.newBuilder()
|
||||
.addQueryParameter("player", username)
|
||||
.build();
|
||||
|
||||
logger.info("Built URL {}", url);
|
||||
|
||||
Request okrequest = new Request.Builder()
|
||||
.url(hiscoreUrl)
|
||||
.build();
|
||||
.url(url)
|
||||
.build();
|
||||
|
||||
Response okresponse = RuneliteAPI.CLIENT.newCall(okrequest).execute();
|
||||
|
||||
if (!okresponse.isSuccessful())
|
||||
{
|
||||
switch (HttpStatus.valueOf(okresponse.code()))
|
||||
{
|
||||
case NOT_FOUND:
|
||||
throw new NotFoundException();
|
||||
default:
|
||||
throw new InternalServerErrorException("Error retrieving data from Jagex Hiscores: " + okresponse.message());
|
||||
}
|
||||
}
|
||||
|
||||
String responseStr;
|
||||
|
||||
try (ResponseBody body = okresponse.body())
|
||||
@@ -85,13 +97,20 @@ public class HiscoreService
|
||||
{
|
||||
if (count++ >= HiscoreSkill.values().length)
|
||||
{
|
||||
logger.warn("Jagex Hiscore API returned unexpected data");
|
||||
break; // rest is other things?
|
||||
}
|
||||
|
||||
// rank, level, experience
|
||||
int rank = Integer.parseInt(record.get(0));
|
||||
int level = Integer.parseInt(record.get(1));
|
||||
long experience = Long.parseLong(record.get(2));
|
||||
|
||||
// items that are not skills do not have an experience parameter
|
||||
long experience = -1;
|
||||
if (record.size() == 3)
|
||||
{
|
||||
experience = Long.parseLong(record.get(2));
|
||||
}
|
||||
|
||||
Skill skill = new Skill(rank, level, experience);
|
||||
hiscoreBuilder.setNextSkill(skill);
|
||||
@@ -100,20 +119,20 @@ public class HiscoreService
|
||||
return hiscoreBuilder;
|
||||
}
|
||||
|
||||
@RequestMapping
|
||||
public HiscoreResult lookup(@RequestParam String username) throws IOException
|
||||
@RequestMapping("/{endpoint}")
|
||||
public HiscoreResult lookup(@PathVariable HiscoreEndpoint endpoint, @RequestParam String username) throws IOException
|
||||
{
|
||||
HiscoreResultBuilder result = lookupUsername(username);
|
||||
HiscoreResultBuilder result = lookupUsername(username, endpoint);
|
||||
return result.build();
|
||||
}
|
||||
|
||||
@RequestMapping("/{skillName}")
|
||||
public SingleHiscoreSkillResult singleSkillLookup(@PathVariable String skillName, @RequestParam String username) throws IOException
|
||||
@RequestMapping("/{endpoint}/{skillName}")
|
||||
public SingleHiscoreSkillResult singleSkillLookup(@PathVariable HiscoreEndpoint endpoint, @PathVariable String skillName, @RequestParam String username) throws IOException
|
||||
{
|
||||
HiscoreSkill skill = HiscoreSkill.valueOf(skillName.toUpperCase());
|
||||
|
||||
// RS api only supports looking up all stats
|
||||
HiscoreResultBuilder result = lookupUsername(username);
|
||||
HiscoreResultBuilder result = lookupUsername(username, endpoint);
|
||||
|
||||
// Find the skill to return
|
||||
Skill requested = result.getSkill(skill.ordinal());
|
||||
@@ -126,13 +145,9 @@ public class HiscoreService
|
||||
return skillResult;
|
||||
}
|
||||
|
||||
public HttpUrl getUrl()
|
||||
@InitBinder
|
||||
public void initBinder(WebDataBinder binder)
|
||||
{
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(HttpUrl url)
|
||||
{
|
||||
this.url = url;
|
||||
binder.registerCustomEditor(HiscoreEndpoint.class, new HiscoreEndpointEditor());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package net.runelite.http.service.util;
|
||||
|
||||
import net.runelite.http.api.hiscore.HiscoreEndpoint;
|
||||
|
||||
import java.beans.PropertyEditorSupport;
|
||||
|
||||
public class HiscoreEndpointEditor extends PropertyEditorSupport
|
||||
{
|
||||
@Override
|
||||
public void setAsText(String text) throws IllegalArgumentException
|
||||
{
|
||||
setValue(HiscoreEndpoint.valueOf(text.toUpperCase()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.http.service.util;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.time.Instant;
|
||||
import org.sql2o.converters.Converter;
|
||||
import org.sql2o.converters.ConverterException;
|
||||
|
||||
public class InstantConverter implements Converter<Instant>
|
||||
{
|
||||
@Override
|
||||
public Instant convert(Object val) throws ConverterException
|
||||
{
|
||||
Timestamp ts = (Timestamp) val;
|
||||
return ts.toInstant();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object toDatabaseParam(Instant val)
|
||||
{
|
||||
return Timestamp.from(val);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.http.service.util.exception;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
public class InternalServerErrorException extends RuntimeException
|
||||
{
|
||||
public InternalServerErrorException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.http.service.util.exception;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "Not found")
|
||||
public class NotFoundException extends RuntimeException
|
||||
{
|
||||
|
||||
}
|
||||
@@ -28,6 +28,8 @@ import java.time.Instant;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import net.runelite.http.service.util.InstantConverter;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
package net.runelite.http.service.hiscore;
|
||||
|
||||
import java.io.IOException;
|
||||
import net.runelite.http.api.hiscore.HiscoreEndpoint;
|
||||
import net.runelite.http.api.hiscore.HiscoreResult;
|
||||
import okhttp3.mockwebserver.MockResponse;
|
||||
import okhttp3.mockwebserver.MockWebServer;
|
||||
@@ -36,38 +37,38 @@ import org.junit.Test;
|
||||
public class HiscoreServiceTest
|
||||
{
|
||||
private static final String RESPONSE = "654683,705,1304518\n"
|
||||
+ "679419,50,107181\n"
|
||||
+ "550667,48,85764\n"
|
||||
+ "861497,50,101366\n"
|
||||
+ "891591,48,87843\n"
|
||||
+ "-1,1,4\n"
|
||||
+ "840255,27,10073\n"
|
||||
+ "1371912,10,1310\n"
|
||||
+ "432193,56,199795\n"
|
||||
+ "495638,56,198304\n"
|
||||
+ "514466,37,27502\n"
|
||||
+ "456981,54,159727\n"
|
||||
+ "459159,49,93010\n"
|
||||
+ "1028855,8,823\n"
|
||||
+ "862906,29,12749\n"
|
||||
+ "795020,31,16097\n"
|
||||
+ "673591,5,495\n"
|
||||
+ "352676,51,112259\n"
|
||||
+ "428419,40,37235\n"
|
||||
+ "461887,43,51971\n"
|
||||
+ "598582,1,10\n"
|
||||
+ "638177,1,0\n"
|
||||
+ "516239,9,1000\n"
|
||||
+ "492790,1,0\n"
|
||||
+ "-1,-1\n"
|
||||
+ "-1,-1\n"
|
||||
+ "-1,-1\n"
|
||||
+ "-1,-1\n"
|
||||
+ "-1,-1\n"
|
||||
+ "-1,-1\n"
|
||||
+ "-1,-1\n"
|
||||
+ "-1,-1\n"
|
||||
+ "-1,-1";
|
||||
+ "679419,50,107181\n"
|
||||
+ "550667,48,85764\n"
|
||||
+ "861497,50,101366\n"
|
||||
+ "891591,48,87843\n"
|
||||
+ "-1,1,4\n"
|
||||
+ "840255,27,10073\n"
|
||||
+ "1371912,10,1310\n"
|
||||
+ "432193,56,199795\n"
|
||||
+ "495638,56,198304\n"
|
||||
+ "514466,37,27502\n"
|
||||
+ "456981,54,159727\n"
|
||||
+ "459159,49,93010\n"
|
||||
+ "1028855,8,823\n"
|
||||
+ "862906,29,12749\n"
|
||||
+ "795020,31,16097\n"
|
||||
+ "673591,5,495\n"
|
||||
+ "352676,51,112259\n"
|
||||
+ "428419,40,37235\n"
|
||||
+ "461887,43,51971\n"
|
||||
+ "598582,1,10\n"
|
||||
+ "638177,1,0\n"
|
||||
+ "516239,9,1000\n"
|
||||
+ "492790,1,0\n"
|
||||
+ "-1,-1\n"
|
||||
+ "-1,-1\n"
|
||||
+ "531,1432\n"
|
||||
+ "-1,-1\n"
|
||||
+ "-1,-1\n"
|
||||
+ "-1,-1\n"
|
||||
+ "-1,-1\n"
|
||||
+ "-1,-1\n"
|
||||
+ "254,92";
|
||||
|
||||
private final MockWebServer server = new MockWebServer();
|
||||
|
||||
@@ -86,16 +87,17 @@ public class HiscoreServiceTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLookup() throws Exception
|
||||
public void testNormalLookup() throws Exception
|
||||
{
|
||||
HiscoreService hiscores = new HiscoreService();
|
||||
hiscores.setUrl(server.url("/"));
|
||||
HiscoreTestService hiscores = new HiscoreTestService(server.url("/"));
|
||||
|
||||
HiscoreResult result = hiscores.lookup("zezima");
|
||||
HiscoreResult result = hiscores.lookup(HiscoreEndpoint.NORMAL, "zezima");
|
||||
|
||||
Assert.assertEquals(50, result.getAttack().getLevel());
|
||||
Assert.assertEquals(159727L, result.getFishing().getExperience());
|
||||
Assert.assertEquals(492790, result.getConstruction().getRank());
|
||||
Assert.assertEquals(1432, result.getClueScrollAll().getLevel());
|
||||
Assert.assertEquals(254, result.getClueScrollMaster().getRank());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package net.runelite.http.service.hiscore;
|
||||
|
||||
import net.runelite.http.api.hiscore.HiscoreEndpoint;
|
||||
import okhttp3.HttpUrl;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
class HiscoreTestService extends HiscoreService
|
||||
{
|
||||
private HttpUrl testUrl;
|
||||
|
||||
HiscoreTestService(HttpUrl testUrl)
|
||||
{
|
||||
this.testUrl = testUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
HiscoreResultBuilder lookupUsername(String username, HiscoreEndpoint endpoint) throws IOException
|
||||
{
|
||||
return super.lookupUsername(username, testUrl);
|
||||
}
|
||||
}
|
||||
@@ -25,38 +25,27 @@
|
||||
package net.runelite.client.plugins.hiscore;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.Insets;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.IOException;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.LinkedList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.event.MouseInputAdapter;
|
||||
|
||||
import net.runelite.api.Experience;
|
||||
import net.runelite.client.RuneLite;
|
||||
import net.runelite.client.ui.IconTextField;
|
||||
import net.runelite.client.ui.PluginPanel;
|
||||
import net.runelite.http.api.hiscore.HiscoreClient;
|
||||
import net.runelite.http.api.hiscore.HiscoreResult;
|
||||
import net.runelite.http.api.hiscore.HiscoreSkill;
|
||||
import net.runelite.http.api.hiscore.*;
|
||||
|
||||
import static net.runelite.http.api.hiscore.HiscoreSkill.*;
|
||||
import net.runelite.http.api.hiscore.Skill;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -83,9 +72,10 @@ public class HiscorePanel extends PluginPanel
|
||||
|
||||
private final IconTextField input;
|
||||
|
||||
private final List<JLabel> skillLabels = new LinkedList<>();
|
||||
private final List<JLabel> skillLabels = new ArrayList<>();
|
||||
|
||||
private final JPanel statsPanel = new JPanel();
|
||||
private final ButtonGroup endpointButtonGroup = new ButtonGroup();
|
||||
private final JTextArea details = new JTextArea();
|
||||
|
||||
private final HiscoreClient client = new HiscoreClient();
|
||||
@@ -134,6 +124,7 @@ public class HiscorePanel extends PluginPanel
|
||||
|
||||
input = new IconTextField();
|
||||
input.setIcon(search);
|
||||
input.setFont(labelFont.deriveFont(Font.BOLD));
|
||||
input.addActionListener(e ->
|
||||
{
|
||||
ScheduledExecutorService executor = runelite.getExecutor();
|
||||
@@ -178,6 +169,22 @@ public class HiscorePanel extends PluginPanel
|
||||
gridBag.setConstraints(totalPanel, c);
|
||||
add(totalPanel);
|
||||
|
||||
JPanel minigamePanel = new JPanel();
|
||||
minigamePanel.setBorder(subPanelBorder);
|
||||
// These aren't all on one row because when there's a label with four or more digits it causes the details
|
||||
// panel to change its size for some reason...
|
||||
minigamePanel.setLayout(new GridLayout(2, 3));
|
||||
|
||||
minigamePanel.add(makeSkillPanel(CLUE_SCROLL_ALL.getName(), CLUE_SCROLL_ALL));
|
||||
minigamePanel.add(makeSkillPanel(LAST_MAN_STANDING.getName(), LAST_MAN_STANDING));
|
||||
minigamePanel.add(makeSkillPanel(BOUNTY_HUNTER_ROGUE.getName(), BOUNTY_HUNTER_ROGUE));
|
||||
minigamePanel.add(makeSkillPanel(BOUNTY_HUNTER_HUNTER.getName(), BOUNTY_HUNTER_HUNTER));
|
||||
|
||||
c.gridx = 0;
|
||||
c.gridy = 3;
|
||||
gridBag.setConstraints(minigamePanel, c);
|
||||
add(minigamePanel);
|
||||
|
||||
JPanel detailsPanel = new JPanel();
|
||||
detailsPanel.setBorder(subPanelBorder);
|
||||
detailsPanel.setLayout(new BorderLayout());
|
||||
@@ -197,16 +204,57 @@ public class HiscorePanel extends PluginPanel
|
||||
detailsPanel.add(details, BorderLayout.CENTER);
|
||||
|
||||
c.gridx = 0;
|
||||
c.gridy = 3;
|
||||
// Last item has a nonzero weighty so it will expand to fill vertical space
|
||||
c.weighty = 1;
|
||||
c.gridy = 4;
|
||||
gridBag.setConstraints(detailsPanel, c);
|
||||
add(detailsPanel);
|
||||
|
||||
JPanel endpointPanel = new JPanel();
|
||||
endpointPanel.setBorder(subPanelBorder);
|
||||
|
||||
List<JToggleButton> endpointButtons = new ArrayList<>();
|
||||
|
||||
for (HiscoreEndpoint endpoint : HiscoreEndpoint.values())
|
||||
{
|
||||
try
|
||||
{
|
||||
Icon icon = new ImageIcon(ImageIO.read(HiscorePanel.class.getResourceAsStream(endpoint.name() + ".png")));
|
||||
Icon selected = new ImageIcon(ImageIO.read(HiscorePanel.class.getResourceAsStream(endpoint.name() + "_selected.png")));
|
||||
JToggleButton button = new JToggleButton();
|
||||
button.setIcon(icon);
|
||||
button.setSelectedIcon(selected);
|
||||
button.setPreferredSize(new Dimension(24,24));
|
||||
button.setBackground(Color.WHITE);
|
||||
button.setFocusPainted(false);
|
||||
button.setActionCommand(endpoint.name());
|
||||
button.setToolTipText(endpoint.getName() + " Hiscores");
|
||||
button.addActionListener((e ->
|
||||
{
|
||||
ScheduledExecutorService executor = runelite.getExecutor();
|
||||
executor.execute(this::lookup);
|
||||
}));
|
||||
endpointButtons.add(button);
|
||||
endpointButtonGroup.add(button);
|
||||
endpointPanel.add(button);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
logger.warn(null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
endpointButtons.get(0).setSelected(true);
|
||||
|
||||
c.gridx = 0;
|
||||
c.gridy = 5;
|
||||
// Last item has a nonzero weighty so it will expand to fill vertical space
|
||||
c.weighty = 1;
|
||||
gridBag.setConstraints(endpointPanel, c);
|
||||
add(endpointPanel);
|
||||
}
|
||||
|
||||
private void changeDetail(String skillName, HiscoreSkill skill)
|
||||
{
|
||||
if (result == null)
|
||||
if (result == null || result.getPlayer() == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -216,14 +264,6 @@ public class HiscorePanel extends PluginPanel
|
||||
String text;
|
||||
switch (skillName)
|
||||
{
|
||||
case "Overall":
|
||||
{
|
||||
Skill requestedSkill = result.getOverall();
|
||||
text = "Total Level" + System.lineSeparator()
|
||||
+ "Rank: " + formatter.format(requestedSkill.getRank()) + System.lineSeparator()
|
||||
+ "Total Experience: " + formatter.format(requestedSkill.getExperience());
|
||||
break;
|
||||
}
|
||||
case "Combat":
|
||||
{
|
||||
double combatLevel = Experience.getCombatLevelPrecise(
|
||||
@@ -235,19 +275,50 @@ public class HiscorePanel extends PluginPanel
|
||||
result.getRanged().getLevel(),
|
||||
result.getPrayer().getLevel()
|
||||
);
|
||||
text = "Exact Combat Level: " + formatter.format(combatLevel) + System.lineSeparator()
|
||||
text = "Skill: Combat" + System.lineSeparator()
|
||||
+ "Exact Combat Level: " + formatter.format(combatLevel) + System.lineSeparator()
|
||||
+ "Experience: " + formatter.format(result.getAttack().getExperience()
|
||||
+ result.getStrength().getExperience() + result.getDefence().getExperience()
|
||||
+ result.getHitpoints().getExperience() + result.getMagic().getExperience()
|
||||
+ result.getRanged().getExperience() + result.getPrayer().getExperience());
|
||||
+ result.getStrength().getExperience() + result.getDefence().getExperience()
|
||||
+ result.getHitpoints().getExperience() + result.getMagic().getExperience()
|
||||
+ result.getRanged().getExperience() + result.getPrayer().getExperience());
|
||||
break;
|
||||
}
|
||||
case "Clue Scrolls (all)":
|
||||
{
|
||||
String rank = (result.getClueScrollAll().getRank() == -1) ? "Unranked" : formatter.format(result.getClueScrollAll().getRank());
|
||||
text = "Total Clue Scrolls Completed" + System.lineSeparator()
|
||||
+ "Rank: " + rank;
|
||||
break;
|
||||
}
|
||||
case "Bounty Hunter - Rogue":
|
||||
{
|
||||
String rank = (result.getBountyHunterRogue().getRank() == -1) ? "Unranked" : formatter.format(result.getBountyHunterRogue().getRank());
|
||||
text = "Bounty Hunter - Rogue Kills" + System.lineSeparator()
|
||||
+ "Rank: " + rank;
|
||||
break;
|
||||
}
|
||||
case "Bounty Hunter - Hunter":
|
||||
{
|
||||
String rank = (result.getBountyHunterHunter().getRank() == -1) ? "Unranked" : formatter.format(result.getBountyHunterHunter().getRank());
|
||||
text = "Bounty Hunter - Hunter Kills" + System.lineSeparator()
|
||||
+ "Rank: " + rank;
|
||||
break;
|
||||
}
|
||||
case "Last Man Standing":
|
||||
{
|
||||
String rank = (result.getLastManStanding().getRank() == -1) ? "Unranked" : formatter.format(result.getLastManStanding().getRank());
|
||||
text = "Last Man Standing" + System.lineSeparator()
|
||||
+ "Rank: " + rank;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
Skill requestedSkill = result.getSkill(skill);
|
||||
String rank = (requestedSkill.getRank() == -1) ? "Unranked" : formatter.format(requestedSkill.getRank());
|
||||
String exp = (requestedSkill.getRank() == -1) ? "Unranked" : formatter.format(requestedSkill.getExperience());
|
||||
text = "Skill: " + skillName + System.lineSeparator()
|
||||
+ "Rank: " + formatter.format(requestedSkill.getRank()) + System.lineSeparator()
|
||||
+ "Experience: " + formatter.format(requestedSkill.getExperience());
|
||||
+ "Rank: " + rank + System.lineSeparator()
|
||||
+ "Experience: " + exp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -265,7 +336,7 @@ public class HiscorePanel extends PluginPanel
|
||||
label.putClientProperty(SKILL_NAME, skillName);
|
||||
label.putClientProperty(SKILL, skill);
|
||||
|
||||
String skillIcon = "/skill_icons/" + skillName.toLowerCase() + ".png";
|
||||
String skillIcon = "skill_icons_small/" + skillName.toLowerCase() + ".png";
|
||||
logger.debug("Loading skill icon from {}", skillIcon);
|
||||
|
||||
try
|
||||
@@ -316,11 +387,14 @@ public class HiscorePanel extends PluginPanel
|
||||
|
||||
try
|
||||
{
|
||||
result = client.lookup(lookup);
|
||||
HiscoreEndpoint endpoint = HiscoreEndpoint.valueOf(endpointButtonGroup.getSelection().getActionCommand());
|
||||
logger.debug("Hiscore endpoint " + endpoint.name() + " selected");
|
||||
|
||||
result = client.lookup(lookup, endpoint);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
logger.warn(null, ex);
|
||||
logger.warn("Error fetching Hiscore data " + ex.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -331,18 +405,29 @@ public class HiscorePanel extends PluginPanel
|
||||
|
||||
if (skillName.equals("Combat"))
|
||||
{
|
||||
int combatLevel = Experience.getCombatLevel(
|
||||
result.getAttack().getLevel(),
|
||||
result.getStrength().getLevel(),
|
||||
result.getDefence().getLevel(),
|
||||
result.getHitpoints().getLevel(),
|
||||
result.getMagic().getLevel(),
|
||||
result.getRanged().getLevel(),
|
||||
result.getPrayer().getLevel()
|
||||
);
|
||||
label.setText(Integer.toString(combatLevel));
|
||||
if (result.getPlayer() != null)
|
||||
{
|
||||
int combatLevel = Experience.getCombatLevel(
|
||||
result.getAttack().getLevel(),
|
||||
result.getStrength().getLevel(),
|
||||
result.getDefence().getLevel(),
|
||||
result.getHitpoints().getLevel(),
|
||||
result.getMagic().getLevel(),
|
||||
result.getRanged().getLevel(),
|
||||
result.getPrayer().getLevel()
|
||||
);
|
||||
label.setText(Integer.toString(combatLevel));
|
||||
}
|
||||
else
|
||||
{
|
||||
label.setText("--");
|
||||
}
|
||||
}
|
||||
else if (skill != null)
|
||||
else if (result.getSkill(skill) == null)
|
||||
{
|
||||
label.setText("--");
|
||||
}
|
||||
else if (result.getSkill(skill) != null && result.getSkill(skill).getRank() != -1)
|
||||
{
|
||||
label.setText(Integer.toString(result.getSkill(skill).getLevel()));
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 465 B |
|
After Width: | Height: | Size: 505 B |
|
After Width: | Height: | Size: 280 B |
|
After Width: | Height: | Size: 325 B |
|
After Width: | Height: | Size: 307 B |
|
After Width: | Height: | Size: 331 B |
|
After Width: | Height: | Size: 391 B |
|
After Width: | Height: | Size: 448 B |
|
After Width: | Height: | Size: 325 B |
|
After Width: | Height: | Size: 373 B |
|
After Width: | Height: | Size: 203 B |
|
After Width: | Height: | Size: 225 B |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 297 B |
|
After Width: | Height: | Size: 465 B |
|
After Width: | Height: | Size: 216 B |
|
After Width: | Height: | Size: 220 B |
|
After Width: | Height: | Size: 220 B |
|
After Width: | Height: | Size: 190 B |
|
After Width: | Height: | Size: 373 B |
|
After Width: | Height: | Size: 240 B |
|
After Width: | Height: | Size: 240 B |
|
After Width: | Height: | Size: 201 B |
|
After Width: | Height: | Size: 222 B |
|
After Width: | Height: | Size: 223 B |
|
After Width: | Height: | Size: 277 B |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 231 B |
|
After Width: | Height: | Size: 212 B |
|
After Width: | Height: | Size: 291 B |
|
After Width: | Height: | Size: 321 B |
|
After Width: | Height: | Size: 258 B |
|
After Width: | Height: | Size: 251 B |
|
After Width: | Height: | Size: 546 B |
|
After Width: | Height: | Size: 237 B |
|
After Width: | Height: | Size: 232 B |
|
After Width: | Height: | Size: 169 B |
|
After Width: | Height: | Size: 240 B |
|
After Width: | Height: | Size: 365 B |
|
After Width: | Height: | Size: 433 B |