update to latest and fix style
This commit is contained in:
@@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<groupId>net.runelite</groupId>
|
||||
<artifactId>runelite-parent</artifactId>
|
||||
<version>1.5.12-SNAPSHOT</version>
|
||||
<version>1.5.14-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>cache-client</artifactId>
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<parent>
|
||||
<groupId>net.runelite</groupId>
|
||||
<artifactId>runelite-parent</artifactId>
|
||||
<version>1.5.12-SNAPSHOT</version>
|
||||
<version>1.5.14-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<name>Cache Updater</name>
|
||||
|
||||
2
cache/pom.xml
vendored
2
cache/pom.xml
vendored
@@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<groupId>net.runelite</groupId>
|
||||
<artifactId>runelite-parent</artifactId>
|
||||
<version>1.5.12-SNAPSHOT</version>
|
||||
<version>1.5.14-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>cache</artifactId>
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<parent>
|
||||
<groupId>net.runelite</groupId>
|
||||
<artifactId>runelite-parent</artifactId>
|
||||
<version>1.5.12-SNAPSHOT</version>
|
||||
<version>1.5.14-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<name>Web API</name>
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.api.ge;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import java.io.IOException;
|
||||
import java.util.UUID;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.http.api.RuneLiteAPI;
|
||||
import okhttp3.Call;
|
||||
import okhttp3.Callback;
|
||||
import okhttp3.HttpUrl;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
|
||||
@Slf4j
|
||||
@AllArgsConstructor
|
||||
public class GrandExchangeClient
|
||||
{
|
||||
private static final MediaType JSON = MediaType.parse("application/json");
|
||||
private static final Gson GSON = RuneLiteAPI.GSON;
|
||||
|
||||
private final UUID uuid;
|
||||
|
||||
public void submit(GrandExchangeTrade grandExchangeTrade)
|
||||
{
|
||||
final HttpUrl url = RuneLiteAPI.getApiBase().newBuilder()
|
||||
.addPathSegment("ge")
|
||||
.build();
|
||||
|
||||
Request request = new Request.Builder()
|
||||
.header(RuneLiteAPI.RUNELITE_AUTH, uuid.toString())
|
||||
.post(RequestBody.create(JSON, GSON.toJson(grandExchangeTrade)))
|
||||
.url(url)
|
||||
.build();
|
||||
|
||||
RuneLiteAPI.CLIENT.newCall(request).enqueue(new Callback()
|
||||
{
|
||||
@Override
|
||||
public void onFailure(Call call, IOException e)
|
||||
{
|
||||
log.debug("unable to submit trade", e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Call call, Response response)
|
||||
{
|
||||
log.debug("Submitted trade");
|
||||
response.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.api.ge;
|
||||
|
||||
import java.time.Instant;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class GrandExchangeTrade
|
||||
{
|
||||
private boolean buy;
|
||||
private int itemId;
|
||||
private int quantity;
|
||||
private int price;
|
||||
private Instant time;
|
||||
}
|
||||
@@ -24,6 +24,7 @@
|
||||
*/
|
||||
package net.runelite.http.api.loottracker;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Collection;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
@@ -37,4 +38,5 @@ public class LootRecord
|
||||
private String eventId;
|
||||
private LootRecordType type;
|
||||
private Collection<GameItem> drops;
|
||||
private Instant time;
|
||||
}
|
||||
|
||||
@@ -35,9 +35,9 @@ import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
@Slf4j
|
||||
public class GrandExchangeClient
|
||||
public class OSBGrandExchangeClient
|
||||
{
|
||||
public GrandExchangeResult lookupItem(int itemId) throws IOException
|
||||
public OSBGrandExchangeResult lookupItem(int itemId) throws IOException
|
||||
{
|
||||
final HttpUrl url = RuneLiteAPI.getApiBase().newBuilder()
|
||||
.addPathSegment("osb")
|
||||
@@ -59,7 +59,7 @@ public class GrandExchangeClient
|
||||
}
|
||||
|
||||
final InputStream in = response.body().byteStream();
|
||||
return RuneLiteAPI.GSON.fromJson(new InputStreamReader(in), GrandExchangeResult.class);
|
||||
return RuneLiteAPI.GSON.fromJson(new InputStreamReader(in), OSBGrandExchangeResult.class);
|
||||
}
|
||||
catch (JsonParseException ex)
|
||||
{
|
||||
@@ -28,7 +28,7 @@ import java.time.Instant;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class GrandExchangeResult
|
||||
public class OSBGrandExchangeResult
|
||||
{
|
||||
private int item_id;
|
||||
private int buy_average;
|
||||
@@ -25,10 +25,12 @@
|
||||
package net.runelite.http.api.ws.messages.party;
|
||||
|
||||
import java.util.UUID;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Value;
|
||||
import net.runelite.http.api.ws.WebsocketMessage;
|
||||
|
||||
@Value
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class Join extends WebsocketMessage
|
||||
{
|
||||
private final UUID partyId;
|
||||
|
||||
@@ -25,10 +25,12 @@
|
||||
package net.runelite.http.api.ws.messages.party;
|
||||
|
||||
import java.util.UUID;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Value;
|
||||
import net.runelite.http.api.ws.WebsocketMessage;
|
||||
|
||||
@Value
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class UserJoin extends WebsocketMessage
|
||||
{
|
||||
private final UUID memberId;
|
||||
|
||||
@@ -25,10 +25,12 @@
|
||||
package net.runelite.http.api.ws.messages.party;
|
||||
|
||||
import java.util.UUID;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Value;
|
||||
import net.runelite.http.api.ws.WebsocketMessage;
|
||||
|
||||
@Value
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class UserPart extends WebsocketMessage
|
||||
{
|
||||
private final UUID memberId;
|
||||
|
||||
@@ -24,9 +24,11 @@
|
||||
*/
|
||||
package net.runelite.http.api.ws.messages.party;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Value;
|
||||
|
||||
@Value
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class UserSync extends PartyMemberMessage
|
||||
{
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<parent>
|
||||
<groupId>net.runelite</groupId>
|
||||
<artifactId>runelite-parent</artifactId>
|
||||
<version>1.5.12-SNAPSHOT</version>
|
||||
<version>1.5.14-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<name>Web Service</name>
|
||||
@@ -55,6 +55,10 @@
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
@@ -130,6 +134,11 @@
|
||||
<version>3.7.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<dependencyManagement>
|
||||
|
||||
@@ -25,13 +25,11 @@
|
||||
package net.runelite.http.service;
|
||||
|
||||
import ch.qos.logback.classic.LoggerContext;
|
||||
import com.google.common.base.Strings;
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.naming.Context;
|
||||
import javax.naming.InitialContext;
|
||||
import javax.naming.NamingException;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletContextEvent;
|
||||
import javax.servlet.ServletContextListener;
|
||||
@@ -44,11 +42,17 @@ import okhttp3.Cache;
|
||||
import okhttp3.OkHttpClient;
|
||||
import org.slf4j.ILoggerFactory;
|
||||
import org.slf4j.impl.StaticLoggerBinder;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.web.support.SpringBootServletInitializer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.sql2o.Sql2o;
|
||||
import org.sql2o.converters.Converter;
|
||||
@@ -56,6 +60,7 @@ import org.sql2o.quirks.NoQuirks;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableScheduling
|
||||
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
|
||||
@Slf4j
|
||||
public class SpringBootWebApplication extends SpringBootServletInitializer
|
||||
{
|
||||
@@ -96,35 +101,80 @@ public class SpringBootWebApplication extends SpringBootServletInitializer
|
||||
};
|
||||
}
|
||||
|
||||
private Context getContext() throws NamingException
|
||||
@ConfigurationProperties(prefix = "datasource.runelite")
|
||||
@Bean("dataSourceRuneLite")
|
||||
public DataSourceProperties dataSourceProperties()
|
||||
{
|
||||
Context initCtx = new InitialContext();
|
||||
return (Context) initCtx.lookup("java:comp/env");
|
||||
return new DataSourceProperties();
|
||||
}
|
||||
|
||||
@ConfigurationProperties(prefix = "datasource.runelite-cache")
|
||||
@Bean("dataSourceRuneLiteCache")
|
||||
public DataSourceProperties dataSourcePropertiesCache()
|
||||
{
|
||||
return new DataSourceProperties();
|
||||
}
|
||||
|
||||
@ConfigurationProperties(prefix = "datasource.runelite-tracker")
|
||||
@Bean("dataSourceRuneLiteTracker")
|
||||
public DataSourceProperties dataSourcePropertiesTracker()
|
||||
{
|
||||
return new DataSourceProperties();
|
||||
}
|
||||
|
||||
@Bean(value = "runelite", destroyMethod = "")
|
||||
public DataSource runeliteDataSource(@Qualifier("dataSourceRuneLite") DataSourceProperties dataSourceProperties)
|
||||
{
|
||||
return getDataSource(dataSourceProperties);
|
||||
}
|
||||
|
||||
@Bean(value = "runelite-cache", destroyMethod = "")
|
||||
public DataSource runeliteCache2DataSource(@Qualifier("dataSourceRuneLiteCache") DataSourceProperties dataSourceProperties)
|
||||
{
|
||||
return getDataSource(dataSourceProperties);
|
||||
}
|
||||
|
||||
@Bean(value = "runelite-tracker", destroyMethod = "")
|
||||
public DataSource runeliteTrackerDataSource(@Qualifier("dataSourceRuneLiteTracker") DataSourceProperties dataSourceProperties)
|
||||
{
|
||||
return getDataSource(dataSourceProperties);
|
||||
}
|
||||
|
||||
@Bean("Runelite SQL2O")
|
||||
Sql2o sql2o() throws NamingException
|
||||
public Sql2o sql2o(@Qualifier("runelite") DataSource dataSource)
|
||||
{
|
||||
DataSource dataSource = (DataSource) getContext().lookup("jdbc/runelite");
|
||||
Map<Class, Converter> converters = new HashMap<>();
|
||||
converters.put(Instant.class, new InstantConverter());
|
||||
return new Sql2o(dataSource, new NoQuirks(converters));
|
||||
return createSql2oFromDataSource(dataSource);
|
||||
}
|
||||
|
||||
@Bean("Runelite Cache SQL2O")
|
||||
Sql2o cacheSql2o() throws NamingException
|
||||
public Sql2o cacheSql2o(@Qualifier("runelite-cache") DataSource dataSource)
|
||||
{
|
||||
DataSource dataSource = (DataSource) getContext().lookup("jdbc/runelite-cache2");
|
||||
Map<Class, Converter> converters = new HashMap<>();
|
||||
converters.put(Instant.class, new InstantConverter());
|
||||
return new Sql2o(dataSource, new NoQuirks(converters));
|
||||
return createSql2oFromDataSource(dataSource);
|
||||
}
|
||||
|
||||
@Bean("Runelite XP Tracker SQL2O")
|
||||
Sql2o trackerSql2o() throws NamingException
|
||||
public Sql2o trackerSql2o(@Qualifier("runelite-tracker") DataSource dataSource)
|
||||
{
|
||||
DataSource dataSource = (DataSource) getContext().lookup("jdbc/runelite-tracker");
|
||||
Map<Class, Converter> converters = new HashMap<>();
|
||||
return createSql2oFromDataSource(dataSource);
|
||||
}
|
||||
|
||||
private static DataSource getDataSource(DataSourceProperties dataSourceProperties)
|
||||
{
|
||||
if (!Strings.isNullOrEmpty(dataSourceProperties.getJndiName()))
|
||||
{
|
||||
// Use JNDI provided datasource, which is already configured with pooling
|
||||
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
|
||||
return dataSourceLookup.getDataSource(dataSourceProperties.getJndiName());
|
||||
}
|
||||
else
|
||||
{
|
||||
return dataSourceProperties.initializeDataSourceBuilder().build();
|
||||
}
|
||||
}
|
||||
|
||||
private static Sql2o createSql2oFromDataSource(final DataSource dataSource)
|
||||
{
|
||||
final Map<Class, Converter> converters = new HashMap<>();
|
||||
converters.put(Instant.class, new InstantConverter());
|
||||
return new Sql2o(dataSource, new NoQuirks(converters));
|
||||
}
|
||||
|
||||
@@ -24,22 +24,42 @@
|
||||
*/
|
||||
package net.runelite.http.service;
|
||||
|
||||
import java.util.List;
|
||||
import net.runelite.http.api.RuneLiteAPI;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.json.GsonHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||
|
||||
/**
|
||||
* Configure .js as application/json to trick Cloudflare into caching json responses
|
||||
*/
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
public class SpringContentNegotiationConfigurer extends WebMvcConfigurerAdapter
|
||||
public class SpringWebMvcConfigurer extends WebMvcConfigurerAdapter
|
||||
{
|
||||
/**
|
||||
* Configure .js as application/json to trick Cloudflare into caching json responses
|
||||
*/
|
||||
@Override
|
||||
public void configureContentNegotiation(ContentNegotiationConfigurer configurer)
|
||||
{
|
||||
configurer.mediaType("js", MediaType.APPLICATION_JSON);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use GSON instead of Jackson for JSON serialization
|
||||
* @param converters
|
||||
*/
|
||||
@Override
|
||||
public void extendMessageConverters(List<HttpMessageConverter<?>> converters)
|
||||
{
|
||||
// Could not figure out a better way to force GSON
|
||||
converters.removeIf(MappingJackson2HttpMessageConverter.class::isInstance);
|
||||
|
||||
GsonHttpMessageConverter gsonHttpMessageConverter = new GsonHttpMessageConverter();
|
||||
gsonHttpMessageConverter.setGson(RuneLiteAPI.GSON);
|
||||
converters.add(gsonHttpMessageConverter);
|
||||
}
|
||||
}
|
||||
@@ -45,8 +45,6 @@ import net.runelite.http.api.ws.messages.LoginResponse;
|
||||
import net.runelite.http.service.account.beans.SessionEntry;
|
||||
import net.runelite.http.service.account.beans.UserEntry;
|
||||
import net.runelite.http.service.util.redis.RedisPool;
|
||||
import net.runelite.http.service.ws.SessionManager;
|
||||
import net.runelite.http.service.ws.WSService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -241,12 +239,6 @@ public class AccountService
|
||||
LoginResponse response = new LoginResponse();
|
||||
response.setUsername(username);
|
||||
|
||||
WSService service = SessionManager.findSession(uuid);
|
||||
if (service != null)
|
||||
{
|
||||
service.send(response);
|
||||
}
|
||||
|
||||
try (Jedis jedis = jedisPool.getResource())
|
||||
{
|
||||
jedis.publish("session." + uuid, websocketGson.toJson(response, WebsocketMessage.class));
|
||||
@@ -276,10 +268,4 @@ public class AccountService
|
||||
{
|
||||
auth.handle(request, response);
|
||||
}
|
||||
|
||||
@RequestMapping("/wscount")
|
||||
public int wscount()
|
||||
{
|
||||
return SessionManager.getCount();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ import java.io.InputStream;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.cache.ConfigType;
|
||||
@@ -233,6 +234,11 @@ public class CacheService
|
||||
public List<ItemDefinition> getItems() throws IOException
|
||||
{
|
||||
CacheEntry cache = findMostRecent();
|
||||
if (cache == null)
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
IndexEntry indexEntry = findIndexForCache(cache, IndexType.CONFIGS.getNumber());
|
||||
ArchiveEntry archiveEntry = findArchiveForIndex(indexEntry, ConfigType.ITEM.getId());
|
||||
ArchiveFiles archiveFiles = getArchiveFiles(archiveEntry);
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import net.runelite.http.api.config.Configuration;
|
||||
import net.runelite.http.service.account.AuthFilter;
|
||||
import net.runelite.http.service.account.beans.SessionEntry;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.DELETE;
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.PUT;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/config")
|
||||
public class ConfigController
|
||||
{
|
||||
private final ConfigService configService;
|
||||
private final AuthFilter authFilter;
|
||||
|
||||
@Autowired
|
||||
public ConfigController(ConfigService configService, AuthFilter authFilter)
|
||||
{
|
||||
this.configService = configService;
|
||||
this.authFilter = authFilter;
|
||||
}
|
||||
|
||||
@RequestMapping
|
||||
public Configuration get(HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
SessionEntry session = authFilter.handle(request, response);
|
||||
|
||||
if (session == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return configService.get(session.getUser());
|
||||
}
|
||||
|
||||
@RequestMapping(path = "/{key:.+}", method = PUT)
|
||||
public void setKey(
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
@PathVariable String key,
|
||||
@RequestBody(required = false) String value
|
||||
) throws IOException
|
||||
{
|
||||
SessionEntry session = authFilter.handle(request, response);
|
||||
|
||||
if (session == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
configService.setKey(session.getUser(), key, value);
|
||||
}
|
||||
|
||||
@RequestMapping(path = "/{key:.+}", method = DELETE)
|
||||
public void unsetKey(
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
@PathVariable String key
|
||||
) throws IOException
|
||||
{
|
||||
SessionEntry session = authFilter.handle(request, response);
|
||||
|
||||
if (session == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
configService.unsetKey(session.getUser(), key);
|
||||
}
|
||||
}
|
||||
@@ -24,28 +24,18 @@
|
||||
*/
|
||||
package net.runelite.http.service.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.annotation.Nullable;
|
||||
import net.runelite.http.api.config.ConfigEntry;
|
||||
import net.runelite.http.api.config.Configuration;
|
||||
import net.runelite.http.service.account.AuthFilter;
|
||||
import net.runelite.http.service.account.beans.SessionEntry;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.DELETE;
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.PUT;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.sql2o.Connection;
|
||||
import org.sql2o.Sql2o;
|
||||
import org.sql2o.Sql2oException;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/config")
|
||||
@Service
|
||||
public class ConfigService
|
||||
{
|
||||
private static final String CREATE_CONFIG = "CREATE TABLE IF NOT EXISTS `config` (\n"
|
||||
@@ -59,16 +49,13 @@ public class ConfigService
|
||||
+ " ADD CONSTRAINT `user_fk` FOREIGN KEY (`user`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;";
|
||||
|
||||
private final Sql2o sql2o;
|
||||
private final AuthFilter auth;
|
||||
|
||||
@Autowired
|
||||
public ConfigService(
|
||||
@Qualifier("Runelite SQL2O") Sql2o sql2o,
|
||||
AuthFilter auth
|
||||
@Qualifier("Runelite SQL2O") Sql2o sql2o
|
||||
)
|
||||
{
|
||||
this.sql2o = sql2o;
|
||||
this.auth = auth;
|
||||
|
||||
try (Connection con = sql2o.open())
|
||||
{
|
||||
@@ -87,71 +74,45 @@ public class ConfigService
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping
|
||||
public Configuration get(HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
public Configuration get(int userId)
|
||||
{
|
||||
SessionEntry session = auth.handle(request, response);
|
||||
|
||||
if (session == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
List<ConfigEntry> config;
|
||||
|
||||
try (Connection con = sql2o.open())
|
||||
{
|
||||
config = con.createQuery("select `key`, value from config where user = :user")
|
||||
.addParameter("user", session.getUser())
|
||||
.addParameter("user", userId)
|
||||
.executeAndFetch(ConfigEntry.class);
|
||||
}
|
||||
|
||||
return new Configuration(config);
|
||||
}
|
||||
|
||||
@RequestMapping(path = "/{key:.+}", method = PUT)
|
||||
public void setKey(
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
@PathVariable String key,
|
||||
@RequestBody(required = false) String value
|
||||
) throws IOException
|
||||
int userId,
|
||||
String key,
|
||||
@Nullable String value
|
||||
)
|
||||
{
|
||||
SessionEntry session = auth.handle(request, response);
|
||||
|
||||
if (session == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try (Connection con = sql2o.open())
|
||||
{
|
||||
con.createQuery("insert into config (user, `key`, value) values (:user, :key, :value) on duplicate key update `key` = :key, value = :value")
|
||||
.addParameter("user", session.getUser())
|
||||
.addParameter("user", userId)
|
||||
.addParameter("key", key)
|
||||
.addParameter("value", value != null ? value : "")
|
||||
.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping(path = "/{key:.+}", method = DELETE)
|
||||
public void unsetKey(
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
@PathVariable String key
|
||||
) throws IOException
|
||||
int userId,
|
||||
String key
|
||||
)
|
||||
{
|
||||
SessionEntry session = auth.handle(request, response);
|
||||
|
||||
if (session == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try (Connection con = sql2o.open())
|
||||
{
|
||||
con.createQuery("delete from config where user = :user and `key` = :key")
|
||||
.addParameter("user", session.getUser())
|
||||
.addParameter("user", userId)
|
||||
.addParameter("key", key)
|
||||
.executeUpdate();
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ public class FeedController
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
log.warn(null, e);
|
||||
log.warn(e.getMessage());
|
||||
}
|
||||
|
||||
try
|
||||
@@ -80,7 +80,7 @@ public class FeedController
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
log.warn(null, e);
|
||||
log.warn(e.getMessage());
|
||||
}
|
||||
|
||||
try
|
||||
@@ -89,7 +89,7 @@ public class FeedController
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
log.warn(null, e);
|
||||
log.warn(e.getMessage());
|
||||
}
|
||||
|
||||
feedResult = new FeedResult(items);
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.ge;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import net.runelite.http.api.ge.GrandExchangeTrade;
|
||||
import net.runelite.http.service.account.AuthFilter;
|
||||
import net.runelite.http.service.account.beans.SessionEntry;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/ge")
|
||||
public class GrandExchangeController
|
||||
{
|
||||
private final GrandExchangeService grandExchangeService;
|
||||
private final AuthFilter authFilter;
|
||||
|
||||
@Autowired
|
||||
public GrandExchangeController(GrandExchangeService grandExchangeService, AuthFilter authFilter)
|
||||
{
|
||||
this.grandExchangeService = grandExchangeService;
|
||||
this.authFilter = authFilter;
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public void submit(HttpServletRequest request, HttpServletResponse response, @RequestBody GrandExchangeTrade grandExchangeTrade) throws IOException
|
||||
{
|
||||
SessionEntry session = authFilter.handle(request, response);
|
||||
|
||||
if (session == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
grandExchangeService.add(session.getUser(), grandExchangeTrade);
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public Collection<GrandExchangeTrade> get(HttpServletRequest request, HttpServletResponse response,
|
||||
@RequestParam(required = false, defaultValue = "1024") int limit,
|
||||
@RequestParam(required = false, defaultValue = "0") int offset) throws IOException
|
||||
{
|
||||
SessionEntry session = authFilter.handle(request, response);
|
||||
|
||||
if (session == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return grandExchangeService.get(session.getUser(), limit, offset).stream()
|
||||
.map(GrandExchangeController::convert)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static GrandExchangeTrade convert(TradeEntry tradeEntry)
|
||||
{
|
||||
GrandExchangeTrade grandExchangeTrade = new GrandExchangeTrade();
|
||||
grandExchangeTrade.setBuy(tradeEntry.getAction() == TradeAction.BUY);
|
||||
grandExchangeTrade.setItemId(tradeEntry.getItem());
|
||||
grandExchangeTrade.setQuantity(tradeEntry.getQuantity());
|
||||
grandExchangeTrade.setPrice(tradeEntry.getPrice());
|
||||
grandExchangeTrade.setTime(tradeEntry.getTime());
|
||||
return grandExchangeTrade;
|
||||
}
|
||||
|
||||
@DeleteMapping
|
||||
public void delete(HttpServletRequest request, HttpServletResponse response) throws IOException
|
||||
{
|
||||
SessionEntry session = authFilter.handle(request, response);
|
||||
|
||||
if (session == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
grandExchangeService.delete(session.getUser());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.ge;
|
||||
|
||||
import java.util.Collection;
|
||||
import net.runelite.http.api.ge.GrandExchangeTrade;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.sql2o.Connection;
|
||||
import org.sql2o.Sql2o;
|
||||
|
||||
@Service
|
||||
public class GrandExchangeService
|
||||
{
|
||||
private static final String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS `ge_trades` (\n" +
|
||||
" `id` int(11) NOT NULL AUTO_INCREMENT,\n" +
|
||||
" `user` int(11) NOT NULL,\n" +
|
||||
" `action` enum('BUY','SELL') NOT NULL,\n" +
|
||||
" `item` int(11) NOT NULL,\n" +
|
||||
" `quantity` int(11) NOT NULL,\n" +
|
||||
" `price` int(11) NOT NULL,\n" +
|
||||
" `time` timestamp NOT NULL DEFAULT current_timestamp(),\n" +
|
||||
" PRIMARY KEY (`id`),\n" +
|
||||
" KEY `user_time` (`user`, `time`),\n" +
|
||||
" KEY `time` (`time`),\n" +
|
||||
" CONSTRAINT `ge_trades_ibfk_1` FOREIGN KEY (`user`) REFERENCES `users` (`id`)\n" +
|
||||
") ENGINE=InnoDB;";
|
||||
|
||||
private final Sql2o sql2o;
|
||||
|
||||
@Autowired
|
||||
public GrandExchangeService(@Qualifier("Runelite SQL2O") Sql2o sql2o)
|
||||
{
|
||||
this.sql2o = sql2o;
|
||||
|
||||
// Ensure necessary tables exist
|
||||
try (Connection con = sql2o.open())
|
||||
{
|
||||
con.createQuery(CREATE_TABLE).executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public void add(int userId, GrandExchangeTrade grandExchangeTrade)
|
||||
{
|
||||
try (Connection con = sql2o.open())
|
||||
{
|
||||
con.createQuery("insert into ge_trades (user, action, item, quantity, price) values (:user," +
|
||||
" :action, :item, :quantity, :price)")
|
||||
.addParameter("user", userId)
|
||||
.addParameter("action", grandExchangeTrade.isBuy() ? "BUY" : "SELL")
|
||||
.addParameter("item", grandExchangeTrade.getItemId())
|
||||
.addParameter("quantity", grandExchangeTrade.getQuantity())
|
||||
.addParameter("price", grandExchangeTrade.getPrice())
|
||||
.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<TradeEntry> get(int userId, int limit, int offset)
|
||||
{
|
||||
try (Connection con = sql2o.open())
|
||||
{
|
||||
return con.createQuery("select id, user, action, item, quantity, price, time from ge_trades where user = :user limit :limit offset :offset")
|
||||
.addParameter("user", userId)
|
||||
.addParameter("limit", limit)
|
||||
.addParameter("offset", offset)
|
||||
.executeAndFetch(TradeEntry.class);
|
||||
}
|
||||
}
|
||||
|
||||
public void delete(int userId)
|
||||
{
|
||||
try (Connection con = sql2o.open())
|
||||
{
|
||||
con.createQuery("delete from ge_trades where user = :user")
|
||||
.addParameter("user", userId)
|
||||
.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@Scheduled(fixedDelay = 60 * 60 * 1000)
|
||||
public void expire()
|
||||
{
|
||||
try (Connection con = sql2o.open())
|
||||
{
|
||||
con.createQuery("delete from ge_trades where time < current_timestamp - interval 1 month")
|
||||
.executeUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.ge;
|
||||
|
||||
enum TradeAction
|
||||
{
|
||||
BUY,
|
||||
SELL;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.ge;
|
||||
|
||||
import java.time.Instant;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
class TradeEntry
|
||||
{
|
||||
private int id;
|
||||
private int user;
|
||||
private TradeAction action;
|
||||
private int item;
|
||||
private int quantity;
|
||||
private int price;
|
||||
private Instant time;
|
||||
}
|
||||
@@ -489,10 +489,16 @@ public class ItemService
|
||||
public void reloadItems() throws IOException
|
||||
{
|
||||
List<ItemDefinition> items = cacheService.getItems();
|
||||
if (items.isEmpty())
|
||||
{
|
||||
log.warn("Failed to load any items from cache, item price updating will be disabled");
|
||||
}
|
||||
|
||||
tradeableItems = items.stream()
|
||||
.filter(item -> item.isTradeable)
|
||||
.mapToInt(item -> item.id)
|
||||
.toArray();
|
||||
|
||||
log.debug("Loaded {} tradeable items", tradeableItems.length);
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ public class LootTrackerController
|
||||
}
|
||||
|
||||
@RequestMapping
|
||||
public Collection<LootRecord> getLootRecords(HttpServletRequest request, HttpServletResponse response, @RequestParam(value = "count", defaultValue = "1024") int count) throws IOException
|
||||
public Collection<LootRecord> getLootRecords(HttpServletRequest request, HttpServletResponse response, @RequestParam(value = "count", defaultValue = "1024") int count, @RequestParam(value = "start", defaultValue = "0") int start) throws IOException
|
||||
{
|
||||
SessionEntry e = auth.handle(request, response);
|
||||
if (e == null)
|
||||
@@ -75,7 +75,7 @@ public class LootTrackerController
|
||||
return null;
|
||||
}
|
||||
|
||||
return service.get(e.getUser(), count);
|
||||
return service.get(e.getUser(), count, start);
|
||||
}
|
||||
|
||||
@DeleteMapping
|
||||
|
||||
@@ -66,7 +66,7 @@ public class LootTrackerService
|
||||
private static final String INSERT_KILL_QUERY = "INSERT INTO kills (accountId, type, eventId) VALUES (:accountId, :type, :eventId)";
|
||||
private static final String INSERT_DROP_QUERY = "INSERT INTO drops (killId, itemId, itemQuantity) VALUES (LAST_INSERT_ID(), :itemId, :itemQuantity)";
|
||||
|
||||
private static final String SELECT_LOOT_QUERY = "SELECT killId,time,type,eventId,itemId,itemQuantity FROM kills JOIN drops ON drops.killId = kills.id WHERE accountId = :accountId ORDER BY TIME DESC LIMIT :limit";
|
||||
private static final String SELECT_LOOT_QUERY = "SELECT killId,time,type,eventId,itemId,itemQuantity FROM kills JOIN drops ON drops.killId = kills.id WHERE accountId = :accountId ORDER BY TIME DESC LIMIT :limit OFFSET :offset";
|
||||
|
||||
private static final String DELETE_LOOT_ACCOUNT = "DELETE FROM kills WHERE accountId = :accountId";
|
||||
private static final String DELETE_LOOT_ACCOUNT_EVENTID = "DELETE FROM kills WHERE accountId = :accountId AND eventId = :eventId";
|
||||
@@ -119,7 +119,7 @@ public class LootTrackerService
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<LootRecord> get(int accountId, int limit)
|
||||
public Collection<LootRecord> get(int accountId, int limit, int offset)
|
||||
{
|
||||
List<LootResult> lootResults;
|
||||
|
||||
@@ -128,6 +128,7 @@ public class LootTrackerService
|
||||
lootResults = con.createQuery(SELECT_LOOT_QUERY)
|
||||
.addParameter("accountId", accountId)
|
||||
.addParameter("limit", limit)
|
||||
.addParameter("offset", offset)
|
||||
.executeAndFetch(LootResult.class);
|
||||
}
|
||||
|
||||
@@ -141,7 +142,7 @@ public class LootTrackerService
|
||||
{
|
||||
if (!gameItems.isEmpty())
|
||||
{
|
||||
LootRecord lootRecord = new LootRecord(current.getEventId(), current.getType(), gameItems);
|
||||
LootRecord lootRecord = new LootRecord(current.getEventId(), current.getType(), gameItems, current.getTime());
|
||||
lootRecords.add(lootRecord);
|
||||
|
||||
gameItems = new ArrayList<>();
|
||||
@@ -156,7 +157,7 @@ public class LootTrackerService
|
||||
|
||||
if (!gameItems.isEmpty())
|
||||
{
|
||||
LootRecord lootRecord = new LootRecord(current.getEventId(), current.getType(), gameItems);
|
||||
LootRecord lootRecord = new LootRecord(current.getEventId(), current.getType(), gameItems, current.getTime());
|
||||
lootRecords.add(lootRecord);
|
||||
}
|
||||
|
||||
|
||||
@@ -35,12 +35,12 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/osb/ge")
|
||||
public class GrandExchangeController
|
||||
public class OSBGrandExchangeController
|
||||
{
|
||||
private final GrandExchangeService grandExchangeService;
|
||||
private final OSBGrandExchangeService grandExchangeService;
|
||||
|
||||
@Autowired
|
||||
public GrandExchangeController(GrandExchangeService grandExchangeService)
|
||||
public OSBGrandExchangeController(OSBGrandExchangeService grandExchangeService)
|
||||
{
|
||||
this.grandExchangeService = grandExchangeService;
|
||||
}
|
||||
@@ -40,7 +40,7 @@ import org.sql2o.Sql2o;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class GrandExchangeService
|
||||
public class OSBGrandExchangeService
|
||||
{
|
||||
private static final String CREATE_GRAND_EXCHANGE_PRICES = "CREATE TABLE IF NOT EXISTS `osb_ge` (\n"
|
||||
+ " `item_id` int(11) NOT NULL,\n"
|
||||
@@ -56,7 +56,7 @@ public class GrandExchangeService
|
||||
private final Sql2o sql2o;
|
||||
|
||||
@Autowired
|
||||
public GrandExchangeService(@Qualifier("Runelite SQL2O") Sql2o sql2o)
|
||||
public OSBGrandExchangeService(@Qualifier("Runelite SQL2O") Sql2o sql2o)
|
||||
{
|
||||
this.sql2o = sql2o;
|
||||
|
||||
@@ -1,100 +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.ws;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import java.util.UUID;
|
||||
import javax.websocket.CloseReason;
|
||||
import javax.websocket.EndpointConfig;
|
||||
import javax.websocket.OnClose;
|
||||
import javax.websocket.OnError;
|
||||
import javax.websocket.OnMessage;
|
||||
import javax.websocket.OnOpen;
|
||||
import javax.websocket.Session;
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.runelite.http.api.ws.WebsocketGsonFactory;
|
||||
import net.runelite.http.api.ws.WebsocketMessage;
|
||||
import net.runelite.http.api.ws.messages.Handshake;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ServerEndpoint("/ws")
|
||||
public class WSService
|
||||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(WSService.class);
|
||||
|
||||
private static final Gson gson = WebsocketGsonFactory.build();
|
||||
|
||||
private Session session;
|
||||
@Getter(AccessLevel.PACKAGE)
|
||||
@Setter(AccessLevel.PACKAGE)
|
||||
private UUID uuid;
|
||||
|
||||
public void send(WebsocketMessage message)
|
||||
{
|
||||
String json = gson.toJson(message, WebsocketMessage.class);
|
||||
|
||||
logger.debug("Sending {}", json);
|
||||
|
||||
session.getAsyncRemote().sendText(json);
|
||||
}
|
||||
|
||||
@OnOpen
|
||||
public void onOpen(Session session, EndpointConfig config)
|
||||
{
|
||||
this.session = session;
|
||||
logger.debug("New session {}", session);
|
||||
}
|
||||
|
||||
@OnClose
|
||||
public void onClose(Session session, CloseReason resaon)
|
||||
{
|
||||
SessionManager.remove(this);
|
||||
logger.debug("Close session {}", session);
|
||||
}
|
||||
|
||||
@OnError
|
||||
public void onError(Session session, Throwable ex)
|
||||
{
|
||||
SessionManager.remove(this);
|
||||
logger.debug("Error in session {}", session, ex);
|
||||
}
|
||||
|
||||
@OnMessage
|
||||
public void onMessage(Session session, String text)
|
||||
{
|
||||
WebsocketMessage message = gson.fromJson(text, WebsocketMessage.class);
|
||||
logger.debug("Got message: {}", message);
|
||||
|
||||
if (message instanceof Handshake)
|
||||
{
|
||||
Handshake hs = (Handshake) message;
|
||||
SessionManager.changeSessionUID(this, hs.getSession());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,8 @@ public interface XpMapper
|
||||
|
||||
XpData xpEntityToXpData(XpEntity xpEntity);
|
||||
|
||||
@Mapping(target = "time", ignore = true)
|
||||
|
||||
@Mapping(source = "attack.experience", target = "attack_xp")
|
||||
@Mapping(source = "defence.experience", target = "defence_xp")
|
||||
@Mapping(source = "strength.experience", target = "strength_xp")
|
||||
|
||||
@@ -29,8 +29,8 @@ import com.google.common.hash.Funnels;
|
||||
import java.nio.charset.Charset;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.http.api.hiscore.HiscoreEndpoint;
|
||||
@@ -50,8 +50,8 @@ import org.sql2o.Sql2o;
|
||||
@Slf4j
|
||||
public class XpTrackerService
|
||||
{
|
||||
private static final int QUEUE_LIMIT = 100_000;
|
||||
private static final Duration UPDATE_TIME = Duration.ofMinutes(5);
|
||||
private static final int QUEUE_LIMIT = 32768;
|
||||
private static final int BLOOMFILTER_EXPECTED_INSERTIONS = 100_000;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("Runelite XP Tracker SQL2O")
|
||||
@@ -60,7 +60,7 @@ public class XpTrackerService
|
||||
@Autowired
|
||||
private HiscoreService hiscoreService;
|
||||
|
||||
private final Queue<String> usernameUpdateQueue = new ConcurrentLinkedDeque<>();
|
||||
private final Queue<String> usernameUpdateQueue = new ArrayDeque<>();
|
||||
private BloomFilter<String> usernameFilter = createFilter();
|
||||
|
||||
public void update(String username) throws ExecutionException
|
||||
@@ -76,13 +76,31 @@ public class XpTrackerService
|
||||
return;
|
||||
}
|
||||
|
||||
if (usernameUpdateQueue.size() >= QUEUE_LIMIT)
|
||||
try (Connection con = sql2o.open())
|
||||
{
|
||||
log.warn("Username update queue is full ({})", QUEUE_LIMIT);
|
||||
return;
|
||||
PlayerEntity playerEntity = findOrCreatePlayer(con, username);
|
||||
Duration frequency = updateFrequency(playerEntity);
|
||||
Instant now = Instant.now();
|
||||
Duration timeSinceLastUpdate = Duration.between(playerEntity.getLast_updated(), now);
|
||||
if (timeSinceLastUpdate.toMillis() < frequency.toMillis())
|
||||
{
|
||||
log.debug("User {} updated too recently", username);
|
||||
usernameFilter.put(username);
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (usernameUpdateQueue)
|
||||
{
|
||||
if (usernameUpdateQueue.size() >= QUEUE_LIMIT)
|
||||
{
|
||||
log.warn("Username update queue is full ({})", QUEUE_LIMIT);
|
||||
return;
|
||||
}
|
||||
|
||||
usernameUpdateQueue.add(username);
|
||||
}
|
||||
}
|
||||
|
||||
usernameUpdateQueue.add(username);
|
||||
usernameFilter.put(username);
|
||||
}
|
||||
|
||||
@@ -104,13 +122,6 @@ public class XpTrackerService
|
||||
log.debug("Hiscore for {} already up to date", username);
|
||||
return;
|
||||
}
|
||||
|
||||
Duration difference = Duration.between(currentXp.getTime(), now);
|
||||
if (difference.compareTo(UPDATE_TIME) <= 0)
|
||||
{
|
||||
log.debug("Updated {} too recently", username);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
con.createQuery("insert into xp (player,attack_xp,defence_xp,strength_xp,hitpoints_xp,ranged_xp,prayer_xp,magic_xp,cooking_xp,woodcutting_xp,"
|
||||
@@ -172,6 +183,11 @@ public class XpTrackerService
|
||||
.addParameter("construction_rank", hiscoreResult.getConstruction().getRank())
|
||||
.addParameter("overall_rank", hiscoreResult.getOverall().getRank())
|
||||
.executeUpdate();
|
||||
|
||||
con.createQuery("update player set rank = :rank, last_updated = CURRENT_TIMESTAMP where id = :id")
|
||||
.addParameter("id", playerEntity.getId())
|
||||
.addParameter("rank", hiscoreResult.getOverall().getRank())
|
||||
.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,6 +213,7 @@ public class XpTrackerService
|
||||
playerEntity.setId(id);
|
||||
playerEntity.setName(username);
|
||||
playerEntity.setTracked_since(now);
|
||||
playerEntity.setLast_updated(now);
|
||||
return playerEntity;
|
||||
}
|
||||
|
||||
@@ -220,18 +237,21 @@ public class XpTrackerService
|
||||
@Scheduled(fixedDelay = 1000)
|
||||
public void update() throws ExecutionException
|
||||
{
|
||||
String next = usernameUpdateQueue.poll();
|
||||
String next;
|
||||
synchronized (usernameUpdateQueue)
|
||||
{
|
||||
next = usernameUpdateQueue.poll();
|
||||
}
|
||||
|
||||
if (next == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
HiscoreResult hiscoreResult = hiscoreService.lookupUsername(next, HiscoreEndpoint.NORMAL);
|
||||
update(next, hiscoreResult);
|
||||
update(next);
|
||||
}
|
||||
|
||||
@Scheduled(fixedDelay = 3 * 60 * 60 * 1000) // 3 hours
|
||||
@Scheduled(fixedDelay = 6 * 60 * 60 * 1000) // 6 hours
|
||||
public void clearFilter()
|
||||
{
|
||||
usernameFilter = createFilter();
|
||||
@@ -241,14 +261,47 @@ public class XpTrackerService
|
||||
{
|
||||
final BloomFilter<String> filter = BloomFilter.create(
|
||||
Funnels.stringFunnel(Charset.defaultCharset()),
|
||||
100_000
|
||||
BLOOMFILTER_EXPECTED_INSERTIONS
|
||||
);
|
||||
|
||||
for (String toUpdate : usernameUpdateQueue)
|
||||
synchronized (usernameUpdateQueue)
|
||||
{
|
||||
filter.put(toUpdate);
|
||||
for (String toUpdate : usernameUpdateQueue)
|
||||
{
|
||||
filter.put(toUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* scale how often to check hiscore updates for players based on their rank
|
||||
* @param playerEntity
|
||||
* @return
|
||||
*/
|
||||
private static Duration updateFrequency(PlayerEntity playerEntity)
|
||||
{
|
||||
Integer rank = playerEntity.getRank();
|
||||
if (rank == null || rank == -1)
|
||||
{
|
||||
return Duration.ofDays(7);
|
||||
}
|
||||
else if (rank < 10_000)
|
||||
{
|
||||
return Duration.ofHours(6);
|
||||
}
|
||||
else if (rank < 50_000)
|
||||
{
|
||||
return Duration.ofDays(2);
|
||||
}
|
||||
else if (rank < 100_000)
|
||||
{
|
||||
return Duration.ofDays(5);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Duration.ofDays(7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,4 +33,6 @@ public class PlayerEntity
|
||||
private Integer id;
|
||||
private String name;
|
||||
private Instant tracked_since;
|
||||
private Instant last_updated;
|
||||
private Integer rank;
|
||||
}
|
||||
|
||||
12
http-service/src/main/resources/application.yaml
Normal file
12
http-service/src/main/resources/application.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
datasource:
|
||||
runelite:
|
||||
jndiName: java:comp/env/jdbc/runelite
|
||||
runelite-cache:
|
||||
jndiName: java:comp/env/jdbc/runelite-cache2
|
||||
runelite-tracker:
|
||||
jndiName: java:comp/env/jdbc/runelite-tracker
|
||||
# By default Spring tries to register the datasource as an MXBean,
|
||||
# so if multiple apis are delpoyed on one web container with
|
||||
# shared datasource it tries to register it multiples times and
|
||||
# fails when starting the 2nd api
|
||||
spring.jmx.enabled: false
|
||||
@@ -1,8 +1,8 @@
|
||||
-- MySQL dump 10.16 Distrib 10.2.9-MariaDB, for Linux (x86_64)
|
||||
-- MySQL dump 10.16 Distrib 10.2.18-MariaDB, for Linux (x86_64)
|
||||
--
|
||||
-- Host: localhost Database: xptracker
|
||||
-- ------------------------------------------------------
|
||||
-- Server version 10.2.9-MariaDB
|
||||
-- Server version 10.2.18-MariaDB
|
||||
|
||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||
@@ -26,6 +26,8 @@ CREATE TABLE `player` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(32) NOT NULL,
|
||||
`tracked_since` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`last_updated` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`rank` int(11) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `name` (`name`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
@@ -116,7 +118,7 @@ CREATE TABLE `xp` (
|
||||
`overall_rank` int(11) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `player_time` (`player`,`time`),
|
||||
INDEX `idx_time` (`time`),
|
||||
KEY `idx_time` (`time`),
|
||||
CONSTRAINT `fk_player` FOREIGN KEY (`player`) REFERENCES `player` (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
@@ -130,4 +132,4 @@ CREATE TABLE `xp` (
|
||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||
|
||||
-- Dump completed on 2018-01-20 18:37:09
|
||||
-- Dump completed on 2019-02-15 21:01:17
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* Copyright (c) 2019, Adam <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -24,57 +24,23 @@
|
||||
*/
|
||||
package net.runelite.http.service;
|
||||
|
||||
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;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.sql2o.Sql2o;
|
||||
import org.sql2o.converters.Converter;
|
||||
import org.sql2o.quirks.NoQuirks;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableScheduling
|
||||
public class SpringBootWebApplicationTest
|
||||
{
|
||||
@Bean("Runelite SQL2O")
|
||||
Sql2o sql2o()
|
||||
{
|
||||
Map<Class, Converter> converters = new HashMap<>();
|
||||
converters.put(Instant.class, new InstantConverter());
|
||||
return new Sql2o("jdbc:mysql://192.168.1.2/runelite", "runelite", "runelite", new NoQuirks(converters));
|
||||
}
|
||||
|
||||
@Bean("Runelite Cache SQL2O")
|
||||
Sql2o cacheSql2o() throws NamingException
|
||||
{
|
||||
Map<Class, Converter> converters = new HashMap<>();
|
||||
converters.put(Instant.class, new InstantConverter());
|
||||
return new Sql2o("jdbc:mysql://192.168.1.2/cache", "runelite", "runelite", new NoQuirks(converters));
|
||||
}
|
||||
|
||||
@Bean("Runelite XP Tracker SQL2O")
|
||||
Sql2o xpSql2o() throws NamingException
|
||||
{
|
||||
Map<Class, Converter> converters = new HashMap<>();
|
||||
converters.put(Instant.class, new InstantConverter());
|
||||
return new Sql2o("jdbc:mysql://192.168.1.2/xptracker", "runelite", "runelite", new NoQuirks(converters));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void test() throws InterruptedException
|
||||
public void run() throws InterruptedException
|
||||
{
|
||||
SpringApplication.run(SpringBootWebApplicationTest.class, new String[0]);
|
||||
String[] args = new String[]{
|
||||
"--spring.config.location=classpath:/application.yaml,classpath:/dev.yaml"
|
||||
};
|
||||
SpringApplication.run(SpringBootWebApplication.class, args);
|
||||
for (;;)
|
||||
{
|
||||
Thread.sleep(100L);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.http.service.account.AuthFilter;
|
||||
import net.runelite.http.service.account.beans.SessionEntry;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@WebMvcTest(ConfigController.class)
|
||||
@Slf4j
|
||||
public class ConfigControllerTest
|
||||
{
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@MockBean
|
||||
private ConfigService configService;
|
||||
|
||||
@MockBean
|
||||
private AuthFilter authFilter;
|
||||
|
||||
@Before
|
||||
public void before() throws IOException
|
||||
{
|
||||
when(authFilter.handle(any(HttpServletRequest.class), any(HttpServletResponse.class)))
|
||||
.thenReturn(mock(SessionEntry.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetKey() throws Exception
|
||||
{
|
||||
mockMvc.perform(put("/config/key")
|
||||
.content("value")
|
||||
.contentType(MediaType.TEXT_PLAIN))
|
||||
.andExpect(status().isOk());
|
||||
|
||||
verify(configService).setKey(anyInt(), eq("key"), eq("value"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.loottracker;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.util.Collections;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.http.api.RuneLiteAPI;
|
||||
import net.runelite.http.api.loottracker.GameItem;
|
||||
import net.runelite.http.api.loottracker.LootRecord;
|
||||
import net.runelite.http.api.loottracker.LootRecordType;
|
||||
import net.runelite.http.service.account.AuthFilter;
|
||||
import net.runelite.http.service.account.beans.SessionEntry;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@WebMvcTest(LootTrackerController.class)
|
||||
@Slf4j
|
||||
public class LootTrackerControllerTest
|
||||
{
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@MockBean
|
||||
private LootTrackerService lootTrackerService;
|
||||
|
||||
@MockBean
|
||||
private AuthFilter authFilter;
|
||||
|
||||
@Before
|
||||
public void before() throws IOException
|
||||
{
|
||||
when(authFilter.handle(any(HttpServletRequest.class), any(HttpServletResponse.class)))
|
||||
.thenReturn(mock(SessionEntry.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void storeLootRecord() throws Exception
|
||||
{
|
||||
LootRecord lootRecord = new LootRecord();
|
||||
lootRecord.setType(LootRecordType.NPC);
|
||||
lootRecord.setTime(Instant.now());
|
||||
lootRecord.setDrops(Collections.singletonList(new GameItem(4151, 1)));
|
||||
|
||||
String data = RuneLiteAPI.GSON.toJson(lootRecord);
|
||||
mockMvc.perform(post("/loottracker").content(data).contentType(MediaType.APPLICATION_JSON))
|
||||
.andExpect(status().isOk());
|
||||
|
||||
verify(lootTrackerService).store(eq(lootRecord), anyInt());
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
oauth.client-id=moo
|
||||
oauth.client-secret=cow
|
||||
minio.endpoint=http://10.96.22.171:9000
|
||||
minio.accesskey=AM54M27O4WZK65N6F8IP
|
||||
minio.secretkey=/PZCxzmsJzwCHYlogcymuprniGCaaLUOET2n6yMP
|
||||
minio.bucket=runelite
|
||||
runelite.twitter.consumerkey=moo
|
||||
runelite.twitter.secretkey=cow
|
||||
runelite.twitter.listid=968949795153948673
|
||||
logging.level.net.runelite=DEBUG
|
||||
spring.jackson.serialization.indent_output=true
|
||||
35
http-service/src/test/resources/application.yaml
Normal file
35
http-service/src/test/resources/application.yaml
Normal file
@@ -0,0 +1,35 @@
|
||||
oauth:
|
||||
client-id: moo
|
||||
client-secret: cow
|
||||
|
||||
minio:
|
||||
endpoint: http://10.96.22.171:9000
|
||||
accesskey: AM54M27O4WZK65N6F8IP
|
||||
secretkey: /PZCxzmsJzwCHYlogcymuprniGCaaLUOET2n6yMP
|
||||
bucket: runelite
|
||||
|
||||
runelite:
|
||||
twitter:
|
||||
consumerkey: moo
|
||||
secretkey: cow
|
||||
listid: 968949795153948673
|
||||
|
||||
logging:
|
||||
level:
|
||||
net:
|
||||
runelite:
|
||||
DEBUG
|
||||
|
||||
datasource:
|
||||
runelite:
|
||||
driverClassName: org.h2.Driver
|
||||
type: org.h2.jdbcx.JdbcDataSource
|
||||
url: jdbc:h2:mem:runelite
|
||||
runelite-cache:
|
||||
driverClassName: org.h2.Driver
|
||||
type: org.h2.jdbcx.JdbcDataSource
|
||||
url: jdbc:h2:mem:cache
|
||||
runelite-tracker:
|
||||
driverClassName: org.h2.Driver
|
||||
type: org.h2.jdbcx.JdbcDataSource
|
||||
url: jdbc:h2:mem:xptracker
|
||||
19
http-service/src/test/resources/dev.yaml
Normal file
19
http-service/src/test/resources/dev.yaml
Normal file
@@ -0,0 +1,19 @@
|
||||
datasource:
|
||||
runelite:
|
||||
driverClassName: com.mysql.jdbc.Driver
|
||||
type: com.mysql.jdbc.jdbc2.optional.MysqlDataSource
|
||||
url: jdbc:mysql://192.168.1.2/runelite
|
||||
username: runelite
|
||||
password: runelite
|
||||
runelite-cache:
|
||||
driverClassName: com.mysql.jdbc.Driver
|
||||
type: com.mysql.jdbc.jdbc2.optional.MysqlDataSource
|
||||
url: jdbc:mysql://192.168.1.2/cache
|
||||
username: runelite
|
||||
password: runelite
|
||||
runelite-tracker:
|
||||
driverClassName: com.mysql.jdbc.Driver
|
||||
type: com.mysql.jdbc.jdbc2.optional.MysqlDataSource
|
||||
url: jdbc:mysql://192.168.1.2/xptracker
|
||||
username: runelite
|
||||
password: runelite
|
||||
2
pom.xml
2
pom.xml
@@ -28,7 +28,7 @@
|
||||
|
||||
<groupId>net.runelite</groupId>
|
||||
<artifactId>runelite-parent</artifactId>
|
||||
<version>1.5.12-SNAPSHOT</version>
|
||||
<version>1.5.14-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>RuneLite</name>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<groupId>net.runelite</groupId>
|
||||
<artifactId>runelite-parent</artifactId>
|
||||
<version>1.5.12-SNAPSHOT</version>
|
||||
<version>1.5.14-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>protocol-api</artifactId>
|
||||
|
||||
@@ -25,8 +25,10 @@
|
||||
package net.runelite.protocol.api.handshake;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class LoginHandshakePacket extends HandshakePacket
|
||||
{
|
||||
|
||||
|
||||
@@ -26,9 +26,11 @@ package net.runelite.protocol.api.handshake;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class UpdateHandshakePacket extends HandshakePacket
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<groupId>net.runelite</groupId>
|
||||
<artifactId>runelite-parent</artifactId>
|
||||
<version>1.5.12-SNAPSHOT</version>
|
||||
<version>1.5.14-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>protocol</artifactId>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<groupId>net.runelite</groupId>
|
||||
<artifactId>runelite-parent</artifactId>
|
||||
<version>1.5.12-SNAPSHOT</version>
|
||||
<version>1.5.14-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>runelite-api</artifactId>
|
||||
|
||||
@@ -123,6 +123,7 @@ public final class AnimationID
|
||||
public static final int HERBLORE_POTIONMAKING = 363; //used for both herb and secondary
|
||||
public static final int MAGIC_CHARGING_ORBS = 726;
|
||||
public static final int MAGIC_MAKE_TABLET = 4068;
|
||||
public static final int MAGIC_ENCHANTING_JEWELRY = 931;
|
||||
public static final int BURYING_BONES = 827;
|
||||
public static final int USING_GILDED_ALTAR = 3705;
|
||||
public static final int LOOKING_INTO = 832;
|
||||
|
||||
@@ -1569,4 +1569,16 @@ public interface Client extends GameEngine
|
||||
int getRasterizer3D_clipMidY2();
|
||||
|
||||
void checkClickbox(Model model, int orientation, int pitchSin, int pitchCos, int yawSin, int yawCos, int x, int y, int z, long hash);
|
||||
|
||||
/**
|
||||
* Sets if a widget is in target mode
|
||||
*/
|
||||
void setSpellSelected(boolean selected);
|
||||
|
||||
/**
|
||||
* Returns client item composition cache
|
||||
*/
|
||||
NodeCache getItemCompositionCache();
|
||||
|
||||
EnumComposition getEnum(int id);
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ public interface DecorativeObject extends TileObject
|
||||
* @see net.runelite.api.model.Jarvis
|
||||
*/
|
||||
Polygon getConvexHull();
|
||||
Polygon getConvexHull2();
|
||||
|
||||
Renderable getRenderable();
|
||||
Renderable getRenderable2();
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.api;
|
||||
|
||||
public interface EnumComposition
|
||||
{
|
||||
int[] getIntVals();
|
||||
|
||||
String[] getStringVals();
|
||||
|
||||
int getIntValue(int key);
|
||||
|
||||
String getStringValue(int key);
|
||||
}
|
||||
@@ -45,6 +45,24 @@ public final class ScriptID
|
||||
*/
|
||||
public static final int CHATBOX_INPUT = 96;
|
||||
|
||||
/**
|
||||
* Opens the Private Message chat interface
|
||||
*
|
||||
* Jagex refers to this script as {@code meslayer_mode6}
|
||||
* <ul>
|
||||
* <li> String Player to send private message to</li>
|
||||
* </ul>
|
||||
*/
|
||||
public static final int OPEN_PRIVATE_MESSAGE_INTERFACE = 107;
|
||||
|
||||
/**
|
||||
* Rebuilds the text input widget inside the chat interface
|
||||
* <ul>
|
||||
* <li> String Message Prefix. Only used inside the GE search interfaces
|
||||
* </ul>
|
||||
*/
|
||||
public static final int CHAT_TEXT_INPUT_REBUILD = 222;
|
||||
|
||||
/**
|
||||
* Layouts the bank widgets
|
||||
*
|
||||
|
||||
@@ -1172,7 +1172,7 @@ public final class SpriteID
|
||||
public static final int MINIMAP_ORB_XP_ACTIVATED = 1197;
|
||||
public static final int MINIMAP_ORB_XP_HOVERED = 1198;
|
||||
public static final int MINIMAP_ORB_XP_ACTIVATED_HOVERED = 1199;
|
||||
public static final int UNKNOWN_BLACK_BLOBS = 1200;
|
||||
public static final int MINIMAP_CLICK_MASK = 1200;
|
||||
public static final int OPTIONS_ZOOM_SLIDER_THUMB = 1201;
|
||||
public static final int EMOTE_SIT_UP = 1202;
|
||||
public static final int EMOTE_STAR_JUMP = 1203;
|
||||
|
||||
@@ -36,6 +36,7 @@ public enum VarClientStr
|
||||
{
|
||||
CHATBOX_TYPED_TEXT(1),
|
||||
INPUT_TEXT(22),
|
||||
PRIVATE_MESSAGE_TARGET(23),
|
||||
RECENT_CLAN_CHAT(129);
|
||||
|
||||
private final int index;
|
||||
|
||||
@@ -37,6 +37,10 @@ public enum VarPlayer
|
||||
ATTACK_STYLE(43),
|
||||
QUEST_POINTS(101),
|
||||
IS_POISONED(102),
|
||||
/**
|
||||
* Seems to start at 50(10 splash) and goes down by 1 every 30 seconds
|
||||
*/
|
||||
DISEASE_VALUE(456),
|
||||
|
||||
BANK_TAB(115),
|
||||
|
||||
|
||||
@@ -25,6 +25,10 @@
|
||||
*/
|
||||
package net.runelite.api.coords;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import lombok.Value;
|
||||
import net.runelite.api.Client;
|
||||
import static net.runelite.api.Constants.CHUNK_SIZE;
|
||||
@@ -150,7 +154,8 @@ public class WorldPoint
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the coordinate of the tile that contains the passed local point.
|
||||
* Gets the coordinate of the tile that contains the passed local point,
|
||||
* accounting for instances.
|
||||
*
|
||||
* @param client the client
|
||||
* @param localPoint the local coordinate
|
||||
@@ -190,6 +195,46 @@ public class WorldPoint
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get occurrences of a tile on the scene, accounting for instances. There may be
|
||||
* more than one if the same template chunk occurs more than once on the scene.
|
||||
* @param client
|
||||
* @param worldPoint
|
||||
* @return
|
||||
*/
|
||||
public static Collection<WorldPoint> toLocalInstance(Client client, WorldPoint worldPoint)
|
||||
{
|
||||
if (!client.isInInstancedRegion())
|
||||
{
|
||||
return Collections.singleton(worldPoint);
|
||||
}
|
||||
|
||||
// find instance chunks using the template point. there might be more than one.
|
||||
List<WorldPoint> worldPoints = new ArrayList<>();
|
||||
final int z = client.getPlane();
|
||||
int[][][] instanceTemplateChunks = client.getInstanceTemplateChunks();
|
||||
for (int x = 0; x < instanceTemplateChunks[z].length; ++x)
|
||||
{
|
||||
for (int y = 0; y < instanceTemplateChunks[z][x].length; ++y)
|
||||
{
|
||||
int chunkData = instanceTemplateChunks[z][x][y];
|
||||
int rotation = chunkData >> 1 & 0x3;
|
||||
int templateChunkY = (chunkData >> 3 & 0x7FF) * CHUNK_SIZE;
|
||||
int templateChunkX = (chunkData >> 14 & 0x3FF) * CHUNK_SIZE;
|
||||
if (worldPoint.getX() >= templateChunkX && worldPoint.getX() < templateChunkX + CHUNK_SIZE
|
||||
&& worldPoint.getY() >= templateChunkY && worldPoint.getY() < templateChunkY + CHUNK_SIZE)
|
||||
{
|
||||
WorldPoint p = new WorldPoint(client.getBaseX() + x * CHUNK_SIZE + (worldPoint.getX() & (CHUNK_SIZE - 1)),
|
||||
client.getBaseY() + y * CHUNK_SIZE + (worldPoint.getY() & (CHUNK_SIZE - 1)),
|
||||
worldPoint.getPlane());
|
||||
p = rotate(p, rotation);
|
||||
worldPoints.add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
return worldPoints;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate the coordinates in the chunk according to chunk rotation
|
||||
*
|
||||
|
||||
@@ -38,6 +38,7 @@ public enum InputType
|
||||
RUNELITE_CHATBOX_PANEL(-3),
|
||||
RUNELITE(-2),
|
||||
NONE(0),
|
||||
PRIVATE_MESSAGE(6),
|
||||
SEARCH(11);
|
||||
|
||||
private final int type;
|
||||
|
||||
@@ -79,6 +79,7 @@ public interface Widget
|
||||
|
||||
/**
|
||||
* Gets the current click configuration of the widget.
|
||||
* @see WidgetConfig
|
||||
*
|
||||
* @see WidgetConfig
|
||||
*/
|
||||
@@ -551,6 +552,13 @@ public interface Widget
|
||||
*/
|
||||
void setOnMouseOverListener(Object... args);
|
||||
|
||||
/**
|
||||
* Sets a script to be ran every frame when the mouse is in the widget bounds
|
||||
*
|
||||
* @param args A ScriptID, then the args for the script
|
||||
*/
|
||||
void setOnMouseRepeatListener(Object... args);
|
||||
|
||||
/**
|
||||
* Sets a script to be ran when the mouse leaves the widget bounds
|
||||
*
|
||||
@@ -565,6 +573,20 @@ public interface Widget
|
||||
*/
|
||||
void setOnTimerListener(Object... args);
|
||||
|
||||
/**
|
||||
* Sets a script to be ran when the target mode has been activated for this widget
|
||||
*
|
||||
* @param args A ScriptID, then the args for the script
|
||||
*/
|
||||
void setOnTargetEnterListener(Object... args);
|
||||
|
||||
/**
|
||||
* Sets a script to be ran when the target mode has been deactivated for this widget
|
||||
*
|
||||
* @param args A ScriptID, then the args for the script
|
||||
*/
|
||||
void setOnTargetLeaveListener(Object... args);
|
||||
|
||||
/**
|
||||
* If this widget has any listeners on it
|
||||
*/
|
||||
@@ -769,4 +791,34 @@ public interface Widget
|
||||
* Sets if the rectangle is filled or just stroked
|
||||
*/
|
||||
void setFilled(boolean filled);
|
||||
|
||||
/**
|
||||
* Verb for spell targets
|
||||
*/
|
||||
String getTargetVerb();
|
||||
|
||||
/**
|
||||
* Verb for spell targets
|
||||
*/
|
||||
void setTargetVerb(String targetVerb);
|
||||
|
||||
/**
|
||||
* Can widgets under this widgets be clicked in this widgets bounding box
|
||||
*/
|
||||
boolean getNoClickThrough();
|
||||
|
||||
/**
|
||||
* Can widgets under this widgets be clicked in this widgets bounding box
|
||||
*/
|
||||
void setNoClickThrough(boolean noClickThrough);
|
||||
|
||||
/**
|
||||
* Can widgets under this widgets be scrolled in this widgets bounding box
|
||||
*/
|
||||
boolean getNoScrollThrough();
|
||||
|
||||
/**
|
||||
* Can widgets under this widgets be scrolled in this widgets bounding box
|
||||
*/
|
||||
void setNoScrollThrough(boolean noScrollThrough);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
*/
|
||||
package net.runelite.api.widgets;
|
||||
|
||||
import net.runelite.api.MenuAction;
|
||||
|
||||
/**
|
||||
* Utility class used for defining options to be used on the click mask
|
||||
* of a {@link Widget}.
|
||||
@@ -36,12 +38,61 @@ public class WidgetConfig
|
||||
* Enables displaying a ninth option on a menu.
|
||||
*/
|
||||
public static final int SHOW_MENU_OPTION_NINE = 1 << 9;
|
||||
|
||||
/**
|
||||
* Can this widget be used on a item on the floor
|
||||
*/
|
||||
public static final int USE_GROUND_ITEM = 1 << 11;
|
||||
|
||||
/**
|
||||
* Can this widget be used on a NPC
|
||||
*/
|
||||
public static final int USE_NPC = 2 << 11;
|
||||
|
||||
/**
|
||||
* Can this widget be used on a game object
|
||||
*/
|
||||
public static final int USE_OBJECT = 4 << 11;
|
||||
|
||||
/**
|
||||
* Can this widget be used on a player
|
||||
*/
|
||||
public static final int USE_PLAYER = 8 << 11;
|
||||
|
||||
/**
|
||||
* Can this widget be used on a item in your inventory
|
||||
*/
|
||||
public static final int USE_ITEM = 16 << 11;
|
||||
|
||||
/**
|
||||
* Can this widget be used on a widget with the WIDGET_USE_TARGET flag
|
||||
*/
|
||||
public static final int USE_WIDGET = 32 << 11;
|
||||
|
||||
/**
|
||||
* Controls whether or not a widget can have another dragged onto it.
|
||||
*/
|
||||
public static final int DRAG_ON = 1 << 17;
|
||||
|
||||
/**
|
||||
* Controls whether or not a widget can be dragged around.
|
||||
*/
|
||||
public static final int DRAG = 1 << 20;
|
||||
|
||||
/**
|
||||
* Can widgets with USE_WIDGET be used on this widget
|
||||
*/
|
||||
public static final int WIDGET_USE_TARGET = 1 << 21;
|
||||
|
||||
/**
|
||||
* Is the widget an (inventory?) item
|
||||
*/
|
||||
public static final int ITEM = 1 << 30;
|
||||
|
||||
/**
|
||||
* Add a USE option
|
||||
*
|
||||
* @see MenuAction#ITEM_USE
|
||||
*/
|
||||
public static final int ITEM_USE_OP = 1 << 31;
|
||||
}
|
||||
|
||||
@@ -125,6 +125,8 @@ public class WidgetID
|
||||
public static final int SKOTIZO_GROUP_ID = 308;
|
||||
public static final int ENTERING_HOUSE_GROUP_ID = 71;
|
||||
public static final int FULLSCREEN_MAP_GROUP_ID = 165;
|
||||
public static final int QUESTLIST_GROUP_ID = 399;
|
||||
public static final int SKILLS_GROUP_ID = 320;
|
||||
|
||||
static class WorldMap
|
||||
{
|
||||
@@ -292,6 +294,7 @@ public class WidgetID
|
||||
static final int TOGGLE_RUN_ORB = 22; // Has the "Toggle run" name
|
||||
static final int RUN_ORB_TEXT = 23;
|
||||
static final int SPEC_ORB = 28;
|
||||
static final int WORLDMAP_ORB = 40;
|
||||
}
|
||||
|
||||
static class LoginClickToPlayScreen
|
||||
@@ -747,4 +750,11 @@ public class WidgetID
|
||||
{
|
||||
static final int ROOT = 25;
|
||||
}
|
||||
|
||||
static class QuestList
|
||||
{
|
||||
static final int FREE_CONTAINER = 9;
|
||||
static final int MEMBERS_CONTAINER = 10;
|
||||
static final int MINIQUEST_CONTAINER = 11;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,6 +159,7 @@ public enum WidgetInfo
|
||||
MINIMAP_RUN_ORB_TEXT(WidgetID.MINIMAP_GROUP_ID, WidgetID.Minimap.RUN_ORB_TEXT),
|
||||
MINIMAP_HEALTH_ORB(WidgetID.MINIMAP_GROUP_ID, WidgetID.Minimap.HEALTH_ORB),
|
||||
MINIMAP_SPEC_ORB(WidgetID.MINIMAP_GROUP_ID, WidgetID.Minimap.SPEC_ORB),
|
||||
MINIMAP_WORLDMAP_ORB(WidgetID.MINIMAP_GROUP_ID, WidgetID.Minimap.WORLDMAP_ORB),
|
||||
|
||||
LOGIN_CLICK_TO_PLAY_SCREEN(WidgetID.LOGIN_CLICK_TO_PLAY_GROUP_ID, 0),
|
||||
LOGIN_CLICK_TO_PLAY_SCREEN_MESSAGE_OF_THE_DAY(WidgetID.LOGIN_CLICK_TO_PLAY_GROUP_ID, WidgetID.LoginClickToPlayScreen.MESSAGE_OF_THE_DAY),
|
||||
@@ -463,7 +464,11 @@ public enum WidgetInfo
|
||||
|
||||
SKOTIZO_CONTAINER(WidgetID.SKOTIZO_GROUP_ID, WidgetID.Skotizo.CONTAINER),
|
||||
|
||||
FULLSCREEN_MAP_ROOT(WidgetID.FULLSCREEN_MAP_GROUP_ID, WidgetID.FullScreenMap.ROOT);
|
||||
FULLSCREEN_MAP_ROOT(WidgetID.FULLSCREEN_MAP_GROUP_ID, WidgetID.FullScreenMap.ROOT),
|
||||
|
||||
QUESTLIST_FREE_CONTAINER(WidgetID.QUESTLIST_GROUP_ID, WidgetID.QuestList.FREE_CONTAINER),
|
||||
QUESTLIST_MEMBERS_CONTAINER(WidgetID.QUESTLIST_GROUP_ID, WidgetID.QuestList.MEMBERS_CONTAINER),
|
||||
QUESTLIST_MINIQUEST_CONTAINER(WidgetID.QUESTLIST_GROUP_ID, WidgetID.QuestList.MINIQUEST_CONTAINER);
|
||||
|
||||
private final int groupId;
|
||||
private final int childId;
|
||||
|
||||
@@ -27,9 +27,12 @@ package net.runelite.api.widgets;
|
||||
public final class WidgetType
|
||||
{
|
||||
public static final int LAYER = 0;
|
||||
public static final int INVENTORY = 2;
|
||||
public static final int RECTANGLE = 3;
|
||||
public static final int TEXT = 4;
|
||||
public static final int GRAPHIC = 5;
|
||||
public static final int MODEL = 6;
|
||||
public static final int TEXT_INVENTORY = 7;
|
||||
public static final int IF1_TOOLTIP = 8;
|
||||
public static final int LINE = 9;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<parent>
|
||||
<groupId>net.runelite</groupId>
|
||||
<artifactId>runelite-parent</artifactId>
|
||||
<version>1.5.12-SNAPSHOT</version>
|
||||
<version>1.5.14-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>client</artifactId>
|
||||
|
||||
@@ -183,9 +183,9 @@ public class RuneLite
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
final boolean developerMode = options.has("developer-mode");
|
||||
final boolean developerMode = options.has("developer-mode") && RuneLiteProperties.getLauncherVersion() == null;
|
||||
|
||||
if (developerMode && RuneLiteProperties.getLauncherVersion() == null)
|
||||
if (developerMode)
|
||||
{
|
||||
boolean assertions = false;
|
||||
assert assertions = true;
|
||||
|
||||
@@ -43,8 +43,11 @@ import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.nio.channels.FileLock;
|
||||
import java.nio.charset.Charset;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -70,6 +73,7 @@ import net.runelite.http.api.config.Configuration;
|
||||
public class ConfigManager
|
||||
{
|
||||
private static final String SETTINGS_FILE_NAME = "settings.properties";
|
||||
private static final DateFormat TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
|
||||
|
||||
@Inject
|
||||
EventBus eventBus;
|
||||
@@ -111,12 +115,17 @@ public class ConfigManager
|
||||
load(); // load profile specific config
|
||||
}
|
||||
|
||||
private File getLocalPropertiesFile()
|
||||
{
|
||||
return new File(RuneLite.RUNELITE_DIR, SETTINGS_FILE_NAME);
|
||||
}
|
||||
|
||||
private File getPropertiesFile()
|
||||
{
|
||||
// Sessions that aren't logged in have no username
|
||||
if (session == null || session.getUsername() == null)
|
||||
{
|
||||
return new File(RuneLite.RUNELITE_DIR, SETTINGS_FILE_NAME);
|
||||
return getLocalPropertiesFile();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -158,7 +167,13 @@ public class ConfigManager
|
||||
for (ConfigEntry entry : configuration.getConfig())
|
||||
{
|
||||
log.debug("Loading configuration value from client {}: {}", entry.getKey(), entry.getValue());
|
||||
final String[] split = entry.getKey().split("\\.");
|
||||
final String[] split = entry.getKey().split("\\.", 2);
|
||||
|
||||
if (split.length != 2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
final String groupName = split[0];
|
||||
final String key = split[1];
|
||||
final String value = entry.getValue();
|
||||
@@ -174,7 +189,7 @@ public class ConfigManager
|
||||
|
||||
try
|
||||
{
|
||||
saveToFile();
|
||||
saveToFile(propertiesFile);
|
||||
|
||||
log.debug("Updated configuration on disk with the latest version");
|
||||
}
|
||||
@@ -184,6 +199,75 @@ public class ConfigManager
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void syncPropertiesFromFile(File propertiesFile)
|
||||
{
|
||||
final Properties properties = new Properties();
|
||||
try (FileInputStream in = new FileInputStream(propertiesFile))
|
||||
{
|
||||
properties.load(new InputStreamReader(in, Charset.forName("UTF-8")));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.debug("Malformed properties, skipping update");
|
||||
return;
|
||||
}
|
||||
|
||||
final Map<String, String> copy = (Map) ImmutableMap.copyOf(this.properties);
|
||||
copy.forEach((groupAndKey, value) ->
|
||||
{
|
||||
if (!properties.containsKey(groupAndKey))
|
||||
{
|
||||
final String[] split = groupAndKey.split("\\.", 2);
|
||||
if (split.length != 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final String groupName = split[0];
|
||||
final String key = split[1];
|
||||
unsetConfiguration(groupName, key);
|
||||
}
|
||||
});
|
||||
|
||||
properties.forEach((objGroupAndKey, objValue) ->
|
||||
{
|
||||
final String groupAndKey = String.valueOf(objGroupAndKey);
|
||||
final String[] split = groupAndKey.split("\\.", 2);
|
||||
if (split.length != 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final String groupName = split[0];
|
||||
final String key = split[1];
|
||||
final String value = String.valueOf(objValue);
|
||||
setConfiguration(groupName, key, value);
|
||||
});
|
||||
}
|
||||
|
||||
public void importLocal()
|
||||
{
|
||||
if (session == null)
|
||||
{
|
||||
// No session, no import
|
||||
return;
|
||||
}
|
||||
|
||||
final File file = new File(propertiesFile.getParent(), propertiesFile.getName() + "." + TIME_FORMAT.format(new Date()));
|
||||
|
||||
try
|
||||
{
|
||||
saveToFile(file);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
log.warn("Backup failed, skipping import", e);
|
||||
return;
|
||||
}
|
||||
|
||||
syncPropertiesFromFile(getLocalPropertiesFile());
|
||||
}
|
||||
|
||||
private synchronized void loadFromFile()
|
||||
{
|
||||
properties.clear();
|
||||
@@ -231,7 +315,7 @@ public class ConfigManager
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void saveToFile() throws IOException
|
||||
private synchronized void saveToFile(final File propertiesFile) throws IOException
|
||||
{
|
||||
propertiesFile.getParentFile().mkdirs();
|
||||
|
||||
@@ -294,8 +378,6 @@ public class ConfigManager
|
||||
|
||||
public void setConfiguration(String groupName, String key, String value)
|
||||
{
|
||||
log.debug("Setting configuration value for {}.{} to {}", groupName, key, value);
|
||||
|
||||
String oldValue = (String) properties.setProperty(groupName + "." + key, value);
|
||||
|
||||
if (Objects.equals(oldValue, value))
|
||||
@@ -303,6 +385,8 @@ public class ConfigManager
|
||||
return;
|
||||
}
|
||||
|
||||
log.debug("Setting configuration value for {}.{} to {}", groupName, key, value);
|
||||
|
||||
synchronized (pendingChanges)
|
||||
{
|
||||
pendingChanges.put(groupName + "." + key, value);
|
||||
@@ -312,7 +396,7 @@ public class ConfigManager
|
||||
{
|
||||
try
|
||||
{
|
||||
saveToFile();
|
||||
saveToFile(propertiesFile);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
@@ -337,8 +421,6 @@ public class ConfigManager
|
||||
|
||||
public void unsetConfiguration(String groupName, String key)
|
||||
{
|
||||
log.debug("Unsetting configuration value for {}.{}", groupName, key);
|
||||
|
||||
String oldValue = (String) properties.remove(groupName + "." + key);
|
||||
|
||||
if (oldValue == null)
|
||||
@@ -346,6 +428,8 @@ public class ConfigManager
|
||||
return;
|
||||
}
|
||||
|
||||
log.debug("Unsetting configuration value for {}.{}", groupName, key);
|
||||
|
||||
synchronized (pendingChanges)
|
||||
{
|
||||
pendingChanges.put(groupName + "." + key, null);
|
||||
@@ -355,7 +439,7 @@ public class ConfigManager
|
||||
{
|
||||
try
|
||||
{
|
||||
saveToFile();
|
||||
saveToFile(propertiesFile);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
|
||||
@@ -78,7 +78,7 @@ public class DiscordService implements AutoCloseable
|
||||
discordRPC = DiscordRPC.INSTANCE;
|
||||
discordEventHandlers = new DiscordEventHandlers();
|
||||
}
|
||||
catch (UnsatisfiedLinkError e)
|
||||
catch (Error e)
|
||||
{
|
||||
log.warn("Failed to load Discord library, Discord support will be disabled.");
|
||||
}
|
||||
@@ -150,9 +150,12 @@ public class DiscordService implements AutoCloseable
|
||||
? "default"
|
||||
: discordPresence.getLargeImageKey();
|
||||
discordRichPresence.largeImageText = discordPresence.getLargeImageText();
|
||||
discordRichPresence.smallImageKey = Strings.isNullOrEmpty(discordPresence.getSmallImageKey())
|
||||
? "default"
|
||||
: discordPresence.getSmallImageKey();
|
||||
|
||||
if (!Strings.isNullOrEmpty(discordPresence.getSmallImageKey()))
|
||||
{
|
||||
discordRichPresence.smallImageKey = discordPresence.getSmallImageKey();
|
||||
}
|
||||
|
||||
discordRichPresence.smallImageText = discordPresence.getSmallImageText();
|
||||
discordRichPresence.partyId = discordPresence.getPartyId();
|
||||
discordRichPresence.partySize = discordPresence.getPartySize();
|
||||
|
||||
@@ -25,8 +25,10 @@
|
||||
package net.runelite.client.events;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public abstract class ChatboxInput extends ChatInput
|
||||
{
|
||||
private final String value;
|
||||
|
||||
@@ -25,8 +25,10 @@
|
||||
package net.runelite.client.events;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public abstract class PrivateMessageInput extends ChatInput
|
||||
{
|
||||
private final String target;
|
||||
|
||||
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* Copyright (c) 2018, SomeoneWithAnInternetConnection
|
||||
* Copyright (c) 2019, MrGroggle
|
||||
* 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.client.game;
|
||||
|
||||
import lombok.Getter;
|
||||
import static net.runelite.api.NullObjectID.*;
|
||||
import static net.runelite.api.ObjectID.*;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
|
||||
@Getter
|
||||
public enum AgilityShortcut
|
||||
{
|
||||
GENERIC_SHORTCUT(1, "Shortcut", null,
|
||||
// Trollheim
|
||||
ROCKS_3790, ROCKS_3791,
|
||||
// Fremennik Slayer Cave
|
||||
STEPS_29993,
|
||||
// Fossil Island
|
||||
LADDER_30938, LADDER_30939, LADDER_30940, LADDER_30941, RUBBER_CAP_MUSHROOM,
|
||||
// Brimhaven dungeon
|
||||
CREVICE_30198,
|
||||
// Lumbridge
|
||||
STILE_12982,
|
||||
// Gu'Tanoth Bridge
|
||||
GAP, GAP_2831,
|
||||
// Lumbridge Swamp Caves
|
||||
STEPPING_STONE_5948, STEPPING_STONE_5949, ROCKS_6673,
|
||||
// Morytania Pirate Ship
|
||||
ROCK_16115,
|
||||
// Lumber Yard
|
||||
BROKEN_FENCE_2618,
|
||||
// McGrubor's Wood
|
||||
LOOSE_RAILING,
|
||||
// Underwater Area Fossil Island
|
||||
TUNNEL_30959, HOLE_30966, OBSTACLE, OBSTACLE_30767, OBSTACLE_30964, OBSTACLE_30962,
|
||||
// Tree Gnome Village
|
||||
LOOSE_RAILING_2186,
|
||||
// Burgh de Rott
|
||||
LOW_FENCE,
|
||||
// Taverley
|
||||
STILE,
|
||||
// Asgarnian Ice Dungeon
|
||||
STEPS,
|
||||
// Fossil Island Wyvern Cave
|
||||
STAIRS_31485),
|
||||
BRIMHAVEN_DUNGEON_MEDIUM_PIPE_RETURN(1, "Pipe Squeeze", null, new WorldPoint(2698, 9491, 0), PIPE_21727),
|
||||
BRIMHAVEN_DUNGEON_PIPE_RETURN(1, "Pipe Squeeze", null, new WorldPoint(2655, 9573, 0), PIPE_21728),
|
||||
BRIMHAVEN_DUNGEON_STEPPING_STONES_RETURN(1, "Pipe Squeeze", null, STEPPING_STONE_21739),
|
||||
BRIMHAVEN_DUNGEON_LOG_BALANCE_RETURN(1, "Log Balance", null, LOG_BALANCE_20884),
|
||||
AGILITY_PYRAMID_ROCKS_WEST(1, "Rocks", null, CLIMBING_ROCKS_11948),
|
||||
CAIRN_ISLE_CLIMBING_ROCKS(1, "Rocks", null, CLIMBING_ROCKS),
|
||||
KARAMJA_GLIDER_LOG(1, "Log Balance", new WorldPoint(2906, 3050, 0), A_WOODEN_LOG ),
|
||||
FALADOR_CRUMBLING_WALL(5, "Crumbling Wall", new WorldPoint(2936, 3357, 0), CRUMBLING_WALL_24222 ),
|
||||
RIVER_LUM_GRAPPLE_WEST(8, "Grapple Broken Raft", new WorldPoint(3245, 3179, 0), BROKEN_RAFT),
|
||||
RIVER_LUM_GRAPPLE_EAST(8, "Grapple Broken Raft", new WorldPoint(3258, 3179, 0), BROKEN_RAFT),
|
||||
CORSAIR_COVE_ROCKS(10, "Rocks", new WorldPoint(2545, 2871, 0), ROCKS_31757),
|
||||
KARAMJA_MOSS_GIANT_SWING(10, "Rope", null, ROPESWING_23568, ROPESWING_23569),
|
||||
FALADOR_GRAPPLE_WALL(11, "Grapple Wall", new WorldPoint(3031, 3391, 0), WALL_17049, WALL_17050),
|
||||
BRIMHAVEN_DUNGEON_STEPPING_STONES(12, "Stepping Stones", null, STEPPING_STONE_21738),
|
||||
VARROCK_SOUTH_FENCE(13, "Fence", new WorldPoint(3239, 3334, 0), FENCE_16518),
|
||||
GOBLIN_VILLAGE_WALL(14, "Wall", new WorldPoint(2925, 3523, 0), TIGHTGAP),
|
||||
CORSAIR_COVE_DUNGEON_PILLAR(15, "Pillar Jump", new WorldPoint(1980, 8996, 0), PILLAR_31809),
|
||||
EDGEVILLE_DUNGEON_MONKEYBARS(15, "Monkey Bars", null, MONKEYBARS_23566),
|
||||
TROLLHEIM_ROCKS(15, "Rocks", null, new WorldPoint(2838, 3614, 0), ROCKS_3748), // No fixed world map location, but rocks near death plateau have a requirement of 15
|
||||
YANILLE_UNDERWALL_TUNNEL(16, "Underwall Tunnel", new WorldPoint(2574, 3109, 0), HOLE_16520, WALL_17047),
|
||||
YANILLE_WATCHTOWER_TRELLIS(18, "Trellis", null, TRELLIS_20056),
|
||||
COAL_TRUCKS_LOG_BALANCE(20, "Log Balance", new WorldPoint(2598, 3475, 0), LOG_BALANCE_23274),
|
||||
GRAND_EXCHANGE_UNDERWALL_TUNNEL(21, "Underwall Tunnel", new WorldPoint(3139, 3515, 0), UNDERWALL_TUNNEL_16529, UNDERWALL_TUNNEL_16530),
|
||||
BRIMHAVEN_DUNGEON_PIPE(22, "Pipe Squeeze", new WorldPoint(2654, 9569, 0), PIPE_21728),
|
||||
OBSERVATORY_SCALE_CLIFF(23, "Grapple Rocks", new WorldPoint(2447, 3155, 0), NULL_31849),
|
||||
EAGLES_PEAK_ROCK_CLIMB(25, "Rock Climb", new WorldPoint(2320, 3499, 0), ROCKS_19849),
|
||||
FALADOR_UNDERWALL_TUNNEL(26, "Underwall Tunnel", new WorldPoint(2947, 3313, 0), UNDERWALL_TUNNEL, UNDERWALL_TUNNEL_16528),
|
||||
MOUNT_KARUULM_LOWER(29, "Rocks", new WorldPoint(1324, 3782, 0), ROCKS_34397),
|
||||
CORSAIR_COVE_RESOURCE_ROCKS(30, "Rocks", new WorldPoint(2486, 2898, 0), ROCKS_31758, ROCKS_31759),
|
||||
SOUTHEAST_KARAJMA_STEPPING_STONES(30, "Stepping Stones", new WorldPoint(2924, 2946, 0), STEPPING_STONES, STEPPING_STONES_23646, STEPPING_STONES_23647),
|
||||
BRIMHAVEN_DUNGEON_LOG_BALANCE(30, "Log Balance", null, LOG_BALANCE_20882),
|
||||
AGILITY_PYRAMID_ROCKS_EAST(30, "Rocks", null, CLIMBING_ROCKS_11949),
|
||||
DRAYNOR_MANOR_STEPPING_STONES(31, "Stepping Stones", new WorldPoint(3150, 3362, 0), STEPPING_STONE_16533),
|
||||
CATHERBY_CLIFFSIDE_GRAPPLE(32, "Grapple Rock", new WorldPoint(2868, 3429, 0), ROCKS_17042),
|
||||
CAIRN_ISLE_ROCKS(32, "Rocks", null, ROCKS_2231),
|
||||
ARDOUGNE_LOG_BALANCE(33, "Log Balance", new WorldPoint(2602, 3336, 0), LOG_BALANCE_16546, LOG_BALANCE_16547, LOG_BALANCE_16548),
|
||||
BRIMHAVEN_DUNGEON_MEDIUM_PIPE(34, "Pipe Squeeze", null, new WorldPoint(2698, 9501, 0), PIPE_21727),
|
||||
CATHERBY_OBELISK_GRAPPLE(36, "Grapple Rock", new WorldPoint(2841, 3434, 0), CROSSBOW_TREE_17062),
|
||||
GNOME_STRONGHOLD_ROCKS(37, "Rocks", new WorldPoint(2485, 3515, 0), ROCKS_16534, ROCKS_16535),
|
||||
AL_KHARID_MINING_PITCLIFF_SCRAMBLE(38, "Rocks", new WorldPoint(3305, 3315, 0), ROCKS_16549, ROCKS_16550),
|
||||
YANILLE_WALL_GRAPPLE(39, "Grapple Wall", new WorldPoint(2552, 3072, 0), CASTLE_WALL),
|
||||
NEITIZNOT_BRIDGE_REPAIR(40, "Bridge Repair - Quest", new WorldPoint(2315, 3828, 0), ROPE_BRIDGE_21306, ROPE_BRIDGE_21307),
|
||||
KOUREND_LAKE_JUMP_EAST(40, "Stepping Stones", new WorldPoint(1612, 3570, 0), STEPPING_STONE_29729, STEPPING_STONE_29730),
|
||||
KOUREND_LAKE_JUMP_WEST(40, "Stepping Stones", new WorldPoint(1604, 3572, 0), STEPPING_STONE_29729, STEPPING_STONE_29730),
|
||||
YANILLE_DUNGEON_BALANCE(40, "Balancing Ledge", null, BALANCING_LEDGE_23548),
|
||||
TROLLHEIM_EASY_CLIFF_SCRAMBLE(41, "Rocks", new WorldPoint(2869, 3670, 0), ROCKS_16521),
|
||||
DWARVEN_MINE_NARROW_CREVICE(42, "Narrow Crevice", new WorldPoint(3034, 9806, 0), CREVICE_16543),
|
||||
DRAYNOR_UNDERWALL_TUNNEL(42, "Underwall Tunnel", new WorldPoint(3068, 3261, 0), UNDERWALL_TUNNEL_19032, UNDERWALL_TUNNEL_19036),
|
||||
TROLLHEIM_MEDIUM_CLIFF_SCRAMBLE_NORTH(43, "Rocks", new WorldPoint(2886, 3684, 0), ROCKS_3803, ROCKS_3804, ROCKS_16522),
|
||||
TROLLHEIM_MEDIUM_CLIFF_SCRAMBLE_SOUTH(43, "Rocks", new WorldPoint(2876, 3666, 0), ROCKS_3803, ROCKS_3804, ROCKS_16522),
|
||||
TROLLHEIM_ADVANCED_CLIFF_SCRAMBLE(44, "Rocks", new WorldPoint(2907, 3686, 0), ROCKS_16523, ROCKS_3748),
|
||||
KOUREND_RIVER_STEPPING_STONES(45, "Stepping Stones", new WorldPoint(1721, 3509, 0), STEPPING_STONE_29728),
|
||||
TIRANNWN_LOG_BALANCE(45, "Log Balance", null, LOG_BALANCE_3933, LOG_BALANCE_3931, LOG_BALANCE_3930, LOG_BALANCE_3929, LOG_BALANCE_3932),
|
||||
COSMIC_ALTAR_MEDIUM_WALKWAY(46, "Narrow Walkway", new WorldPoint(2399, 4403, 0), JUTTING_WALL_17002),
|
||||
DEEP_WILDERNESS_DUNGEON_CREVICE_NORTH(46, "Narrow Crevice", new WorldPoint(3047, 10335, 0), CREVICE_19043),
|
||||
DEEP_WILDERNESS_DUNGEON_CREVICE_SOUTH(46, "Narrow Crevice", new WorldPoint(3045, 10327, 0), CREVICE_19043),
|
||||
TROLLHEIM_HARD_CLIFF_SCRAMBLE(47, "Rocks", new WorldPoint(2902, 3680, 0), ROCKS_16524),
|
||||
FREMENNIK_LOG_BALANCE(48, "Log Balance", new WorldPoint(2721, 3591, 0), LOG_BALANCE_16540, LOG_BALANCE_16541, LOG_BALANCE_16542),
|
||||
YANILLE_DUNGEON_PIPE_SQUEEZE(49, "Pipe Squeeze", null, OBSTACLE_PIPE_23140),
|
||||
ARCEUUS_ESSENCE_MINE_BOULDER(49, "Boulder", new WorldPoint(1774, 3888, 0), BOULDER_27990),
|
||||
MORYTANIA_STEPPING_STONE(50, "Stepping Stone", new WorldPoint(3418, 3326, 0), STEPPING_STONE_13504),
|
||||
VARROCK_SEWERS_PIPE_SQUEEZE(51, "Pipe Squeeze", new WorldPoint(3152, 9905, 0), OBSTACLE_PIPE_16511),
|
||||
ARCEUUS_ESSENCE_MINE_EAST_SCRAMBLE(52, "Rock Climb", new WorldPoint(1770, 3851, 0), ROCKS_27987, ROCKS_27988),
|
||||
KARAMJA_VOLCANO_GRAPPLE_NORTH(53, "Grapple Rock", new WorldPoint(2873, 3143, 0), STRONG_TREE_17074),
|
||||
KARAMJA_VOLCANO_GRAPPLE_SOUTH(53, "Grapple Rock", new WorldPoint(2874, 3128, 0), STRONG_TREE_17074),
|
||||
MOTHERLODE_MINE_WALL_EAST(54, "Wall", new WorldPoint(3124, 9703, 0), DARK_TUNNEL_10047),
|
||||
MOTHERLODE_MINE_WALL_WEST(54, "Wall", new WorldPoint(3118, 9702, 0), DARK_TUNNEL_10047),
|
||||
MISCELLANIA_DOCK_STEPPING_STONE(55, "Stepping Stone", new WorldPoint(2572, 3862, 0), STEPPING_STONE_11768),
|
||||
ISAFDAR_FOREST_OBSTACLES(56, "Trap", null, DENSE_FOREST_3938, DENSE_FOREST_3939, DENSE_FOREST_3998, DENSE_FOREST_3999, DENSE_FOREST, LEAVES, LEAVES_3924, LEAVES_3925, STICKS, TRIPWIRE),
|
||||
RELEKKA_EAST_FENCE(57, "Fence", new WorldPoint(2688, 3697, 0), BROKEN_FENCE),
|
||||
YANILLE_DUNGEON_MONKEY_BARS(57, "Monkey Bars", null, MONKEYBARS_23567),
|
||||
PHASMATYS_ECTOPOOL_SHORTCUT(58, "Weathered Wall", null , WEATHERED_WALL, WEATHERED_WALL_16526),
|
||||
ELVEN_OVERPASS_CLIFF_SCRAMBLE(59, "Rocks", new WorldPoint(2345, 3300, 0), ROCKS_16514, ROCKS_16515),
|
||||
WILDERNESS_GWD_CLIMB_EAST(60, "Rocks", new WorldPoint(2943, 3770, 0), ROCKY_HANDHOLDS_26400, ROCKY_HANDHOLDS_26401, ROCKY_HANDHOLDS_26402, ROCKY_HANDHOLDS_26404, ROCKY_HANDHOLDS_26405, ROCKY_HANDHOLDS_26406),
|
||||
WILDERNESS_GWD_CLIMB_WEST(60, "Rocks", new WorldPoint(2928, 3760, 0), ROCKY_HANDHOLDS_26400, ROCKY_HANDHOLDS_26401, ROCKY_HANDHOLDS_26402, ROCKY_HANDHOLDS_26404, ROCKY_HANDHOLDS_26405, ROCKY_HANDHOLDS_26406),
|
||||
MOS_LEHARMLESS_STEPPING_STONE(60, "Stepping Stone", new WorldPoint(3710, 2970, 0), STEPPING_STONE_19042),
|
||||
WINTERTODT_GAP(60, "Gap", new WorldPoint(1629, 4023, 0), GAP_29326),
|
||||
UNGAEL_ICE(60, "Ice Chunks", null, NULL_25337, NULL_29868, NULL_29869, NULL_29870, ICE_CHUNKS_31822, NULL_31823, ICE_CHUNKS_31990),
|
||||
SLAYER_TOWER_MEDIUM_CHAIN_FIRST(61, "Spiked Chain (Floor 1)", new WorldPoint(3421, 3550, 0), SPIKEY_CHAIN),
|
||||
SLAYER_TOWER_MEDIUM_CHAIN_SECOND(61, "Spiked Chain (Floor 2)", new WorldPoint(3420, 3551, 0), SPIKEY_CHAIN_16538),
|
||||
SLAYER_DUNGEON_CREVICE(62, "Narrow Crevice", new WorldPoint(2729, 10008, 0), CREVICE_16539),
|
||||
MOUNT_KARUULM_UPPER(62, "Rocks", new WorldPoint(1322, 3791, 0), ROCKS_34396),
|
||||
TAVERLEY_DUNGEON_RAILING(63, "Loose Railing", new WorldPoint(2935, 9811, 0), LOOSE_RAILING_28849),
|
||||
TROLLHEIM_WILDERNESS_ROCKS_EAST(64, "Rocks", new WorldPoint(2945, 3678, 0), ROCKS_16545),
|
||||
TROLLHEIM_WILDERNESS_ROCKS_WEST(64, "Rocks", new WorldPoint(2917, 3672, 0), ROCKS_16545),
|
||||
FOSSIL_ISLAND_VOLCANO(64, "Rope", new WorldPoint(3780, 3822, 0), ROPE_ANCHOR, ROPE_ANCHOR_30917),
|
||||
MORYTANIA_TEMPLE(65, "Loose Railing", new WorldPoint(3422, 3476, 0), ROCKS_16998, ROCKS_16999, ORNATE_RAILING, ORNATE_RAILING_17000),
|
||||
REVENANT_CAVES_GREEN_DRAGONS(65, "Jump", new WorldPoint(3220, 10086, 0), PILLAR_31561),
|
||||
COSMIC_ALTAR_ADVANCED_WALKWAY(66, "Narrow Walkway", new WorldPoint(2408, 4401, 0), JUTTING_WALL_17002),
|
||||
LUMBRIDGE_DESERT_STEPPING_STONE(66, "Stepping Stone", new WorldPoint(3210, 3135, 0), STEPPING_STONE_16513),
|
||||
HEROES_GUILD_TUNNEL_EAST(67, "Crevice", new WorldPoint(2898, 9901, 0), CREVICE_9739, CREVICE_9740),
|
||||
HEROES_GUILD_TUNNEL_WEST(67, "Crevice", new WorldPoint(2913, 9895, 0), CREVICE_9739, CREVICE_9740),
|
||||
YANILLE_DUNGEON_RUBBLE_CLIMB(67, "Pile of Rubble", null, PILE_OF_RUBBLE_23563, PILE_OF_RUBBLE_23564),
|
||||
ELVEN_OVERPASS_MEDIUM_CLIFF(68, "Rocks", new WorldPoint(2337, 3288, 0), ROCKS_16514, ROCKS_16515),
|
||||
WEISS_OBSTACLES(68, "Shortcut", null, LITTLE_BOULDER, ROCKSLIDE_33184, ROCKSLIDE_33185, NULL_33327, NULL_33328, LEDGE_33190, ROCKSLIDE_33191, FALLEN_TREE_33192),
|
||||
ARCEUUS_ESSENSE_NORTH(69, "Rock Climb", new WorldPoint(1759, 3873, 0), ROCKS_27984, ROCKS_27985),
|
||||
TAVERLEY_DUNGEON_PIPE_BLUE_DRAGON(70, "Pipe Squeeze", new WorldPoint(2886, 9798, 0), OBSTACLE_PIPE_16509),
|
||||
TAVERLEY_DUNGEON_ROCKS_NORTH(70, "Rocks", new WorldPoint(2887, 9823, 0), ROCKS, ROCKS_14106),
|
||||
TAVERLEY_DUNGEON_ROCKS_SOUTH(70, "Rocks", new WorldPoint(2887, 9631, 0), ROCKS, ROCKS_14106),
|
||||
FOSSIL_ISLAND_HARDWOOD_NORTH(70, "Hole" , new WorldPoint(3713, 3827, 0), HOLE_31481, HOLE_31482),
|
||||
FOSSIL_ISLAND_HARDWOOD_SOUTH(70, "Hole" , new WorldPoint(3715, 3817, 0), HOLE_31481, HOLE_31482),
|
||||
AL_KHARID_WINDOW(70, "Window", new WorldPoint(3293, 3158, 0), BROKEN_WALL_33344, BIG_WINDOW),
|
||||
GWD_SARADOMIN_ROPE_NORTH(70, "Rope Descent", new WorldPoint(2912, 5300, 0), NULL_26371),
|
||||
GWD_SARADOMIN_ROPE_SOUTH(70, "Rope Descent", new WorldPoint(2951, 5267, 0), NULL_26375),
|
||||
SLAYER_TOWER_ADVANCED_CHAIN_FIRST(71, "Spiked Chain (Floor 2)", new WorldPoint(3447, 3578, 0), SPIKEY_CHAIN ),
|
||||
SLAYER_TOWER_ADVANCED_CHAIN_SECOND(71, "Spiked Chain (Floor 3)", new WorldPoint(3446, 3576, 0), SPIKEY_CHAIN_16538),
|
||||
STRONGHOLD_SLAYER_CAVE_TUNNEL(72, "Tunnel", new WorldPoint(2431, 9806, 0), TUNNEL_30174, TUNNEL_30175),
|
||||
TROLL_STRONGHOLD_WALL_CLIMB(73, "Rocks", new WorldPoint(2841, 3694, 0), ROCKS_16464),
|
||||
ARCEUUS_ESSENSE_MINE_WEST(73, "Rock Climb", new WorldPoint(1742, 3853, 0), ROCKS_27984, ROCKS_27985 ),
|
||||
LAVA_DRAGON_ISLE_JUMP(74, "Stepping Stone", new WorldPoint(3200, 3807, 0), STEPPING_STONE_14918),
|
||||
REVENANT_CAVES_DEMONS_JUMP(75, "Jump", new WorldPoint(3199, 10135, 0), PILLAR_31561),
|
||||
REVENANT_CAVES_ANKOU_EAST(75, "Jump", new WorldPoint(3201, 10195, 0), PILLAR_31561),
|
||||
REVENANT_CAVES_ANKOU_NORTH(75, "Jump", new WorldPoint(3180, 10209, 0), PILLAR_31561),
|
||||
ZUL_ANDRA_ISLAND_CROSSING(76, "Stepping Stone", new WorldPoint(2156, 3073, 0), STEPPING_STONE_10663),
|
||||
SHILO_VILLAGE_STEPPING_STONES( 77, "Stepping Stones", new WorldPoint(2863, 2974, 0), STEPPING_STONE_16466),
|
||||
KHARAZI_JUNGLE_VINE_CLIMB(79, "Vine", new WorldPoint(2897, 2939, 0), NULL_26884, NULL_26886),
|
||||
TAVERLEY_DUNGEON_SPIKED_BLADES(80, "Strange Floor", new WorldPoint(2877, 9813, 0), STRANGE_FLOOR),
|
||||
SLAYER_DUNGEON_CHASM_JUMP(81, "Spiked Blades", new WorldPoint(2770, 10003, 0), STRANGE_FLOOR_16544),
|
||||
LAVA_MAZE_NORTH_JUMP(82, "Stepping Stone", new WorldPoint(3092, 3880, 0), STEPPING_STONE_14917),
|
||||
BRIMHAVEN_DUNGEON_EAST_STEPPING_STONES_NORTH(83, "Stepping Stones", new WorldPoint(2685, 9547, 0), STEPPING_STONE_19040),
|
||||
BRIMHAVEN_DUNGEON_EAST_STEPPING_STONES_SOUTH(83, "Stepping Stones", new WorldPoint(2693, 9529, 0), STEPPING_STONE_19040),
|
||||
ELVEN_ADVANCED_CLIFF_SCRAMBLE(85, "Rocks", new WorldPoint(2337, 3253, 0), ROCKS_16514, ROCKS_16514),
|
||||
KALPHITE_WALL(86, "Crevice", new WorldPoint(3214, 9508, 0), CREVICE_16465),
|
||||
BRIMHAVEN_DUNGEON_VINE_EAST(87, "Vine", new WorldPoint(2672, 9582, 0), VINE_26880, VINE_26882),
|
||||
BRIMHAVEN_DUNGEON_VINE_WEST(87, "Vine", new WorldPoint(2606, 9584, 0), VINE_26880, VINE_26882),
|
||||
REVENANT_CAVES_CHAMBER_JUMP(89, "Jump", new WorldPoint(3240, 10144, 0), PILLAR_31561);
|
||||
|
||||
/**
|
||||
* The agility level required to pass the shortcut
|
||||
*/
|
||||
@Getter
|
||||
private final int level;
|
||||
/**
|
||||
* Brief description of the shortcut (e.g. 'Rocks', 'Stepping Stones', 'Jump')
|
||||
*/
|
||||
@Getter
|
||||
private final String description;
|
||||
/**
|
||||
* The location of the Shortcut icon on the world map (null if there is no icon)
|
||||
*/
|
||||
@Getter
|
||||
private final WorldPoint worldMapLocation;
|
||||
/**
|
||||
* An optional location in case the location of the shortcut icon is either
|
||||
* null or isn't close enough to the obstacle
|
||||
*/
|
||||
@Getter
|
||||
private final WorldPoint worldLocation;
|
||||
/**
|
||||
* Array of obstacles, null objects, decorations etc. that this shortcut uses.
|
||||
* Typically an ObjectID/NullObjectID
|
||||
*/
|
||||
@Getter
|
||||
private final int[] obstacleIds;
|
||||
|
||||
AgilityShortcut(int level, String description, WorldPoint mapLocation, WorldPoint worldLocation, int... obstacleIds)
|
||||
{
|
||||
this.level = level;
|
||||
this.description = description;
|
||||
this.worldMapLocation = mapLocation;
|
||||
this.worldLocation = worldLocation;
|
||||
this.obstacleIds = obstacleIds;
|
||||
}
|
||||
|
||||
AgilityShortcut(int level, String description, WorldPoint location, int... obstacleIds)
|
||||
{
|
||||
this(level, description, location, location, obstacleIds);
|
||||
}
|
||||
|
||||
public String getTooltip()
|
||||
{
|
||||
return description + " - Level " + level;
|
||||
}
|
||||
}
|
||||
@@ -256,6 +256,15 @@ public class ItemManager
|
||||
itemCompositions.put(event.getItemComposition().getId(), event.getItemComposition());
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates internal item manager item composition cache (but not client item composition cache)
|
||||
* @see Client#getItemCompositionCache()
|
||||
*/
|
||||
public void invalidateItemCompositionCache()
|
||||
{
|
||||
itemCompositions.invalidateAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up an item's price
|
||||
*
|
||||
|
||||
@@ -28,6 +28,7 @@ import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.inject.Inject;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
import javax.annotation.Nullable;
|
||||
@@ -36,11 +37,14 @@ import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.SwingUtilities;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.api.SpritePixels;
|
||||
import net.runelite.client.callback.ClientThread;
|
||||
import net.runelite.client.util.ImageUtil;
|
||||
|
||||
@Slf4j
|
||||
@Singleton
|
||||
public class SpriteManager
|
||||
{
|
||||
@@ -127,4 +131,36 @@ public class SpriteManager
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public void addSpriteOverrides(SpriteOverride[] add)
|
||||
{
|
||||
if (add.length <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
clientThread.invokeLater(() ->
|
||||
{
|
||||
Map<Integer, SpritePixels> overrides = client.getSpriteOverrides();
|
||||
Class<?> owner = add[0].getClass();
|
||||
for (SpriteOverride o : add)
|
||||
{
|
||||
BufferedImage image = ImageUtil.getResourceStreamFromClass(owner, o.getFileName());
|
||||
SpritePixels sp = ImageUtil.getImageSpritePixels(image, client);
|
||||
overrides.put(o.getSpriteId(), sp);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void removeSpriteOverrides(SpriteOverride[] remove)
|
||||
{
|
||||
clientThread.invokeLater(() ->
|
||||
{
|
||||
Map<Integer, SpritePixels> overrides = client.getSpriteOverrides();
|
||||
for (SpriteOverride o : remove)
|
||||
{
|
||||
overrides.remove(o.getSpriteId());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Abex
|
||||
* 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.client.game;
|
||||
|
||||
import net.runelite.api.SpriteID;
|
||||
|
||||
public interface SpriteOverride
|
||||
{
|
||||
/**
|
||||
* An ID for a sprite. Negative numbers are used by RuneLite specific sprites
|
||||
*
|
||||
* @see SpriteID
|
||||
*/
|
||||
int getSpriteId();
|
||||
|
||||
/**
|
||||
* The file name for the resource to be loaded, relative to the implementing class
|
||||
*/
|
||||
String getFileName();
|
||||
}
|
||||
@@ -24,7 +24,10 @@
|
||||
*/
|
||||
package net.runelite.client.game.chatbox;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.primitives.Ints;
|
||||
import com.google.inject.Inject;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.datatransfer.DataFlavor;
|
||||
@@ -33,21 +36,25 @@ import java.awt.datatransfer.UnsupportedFlavorException;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.IntPredicate;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.ToIntFunction;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.swing.SwingUtilities;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.FontTypeFace;
|
||||
import net.runelite.api.FontID;
|
||||
import net.runelite.api.widgets.WidgetType;
|
||||
import net.runelite.api.FontTypeFace;
|
||||
import net.runelite.api.widgets.JavaScriptCallback;
|
||||
import net.runelite.api.widgets.Widget;
|
||||
import net.runelite.api.widgets.WidgetPositionMode;
|
||||
import net.runelite.api.widgets.WidgetSizeMode;
|
||||
import net.runelite.api.widgets.WidgetTextAlignment;
|
||||
import net.runelite.api.widgets.WidgetType;
|
||||
import net.runelite.client.callback.ClientThread;
|
||||
import net.runelite.client.input.KeyListener;
|
||||
import net.runelite.client.input.MouseListener;
|
||||
@@ -57,6 +64,7 @@ import net.runelite.client.util.Text;
|
||||
public class ChatboxTextInput extends ChatboxInput implements KeyListener, MouseListener
|
||||
{
|
||||
private static final int CURSOR_FLASH_RATE_MILLIS = 1000;
|
||||
private static final Pattern BREAK_MATCHER = Pattern.compile("[^a-zA-Z0-9']");
|
||||
|
||||
private final ChatboxPanelManager chatboxPanelManager;
|
||||
private final ClientThread clientThread;
|
||||
@@ -66,13 +74,24 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
|
||||
return i -> i >= 32 && i < 127;
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
private static class Line
|
||||
{
|
||||
private final int start;
|
||||
private final int end;
|
||||
private final String text;
|
||||
}
|
||||
|
||||
@Getter
|
||||
private String prompt;
|
||||
|
||||
@Getter
|
||||
private int lines;
|
||||
|
||||
private StringBuffer value = new StringBuffer();
|
||||
|
||||
@Getter
|
||||
private int cursor = 0;
|
||||
private int cursorStart = 0;
|
||||
|
||||
@Getter
|
||||
private int cursorEnd = 0;
|
||||
@@ -95,12 +114,14 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
|
||||
@Getter
|
||||
private int fontID = FontID.QUILL_8;
|
||||
|
||||
// This is a lambda so I can have atomic updates for it's captures
|
||||
private ToIntFunction<MouseEvent> getCharOffset = null;
|
||||
private Predicate<MouseEvent> isInBounds = null;
|
||||
|
||||
@Getter
|
||||
private boolean built = false;
|
||||
|
||||
// These are lambdas for atomic updates
|
||||
private Predicate<MouseEvent> isInBounds = null;
|
||||
private ToIntFunction<Integer> getLineOffset = null;
|
||||
private ToIntFunction<Point> getPointCharOffset = null;
|
||||
|
||||
@Inject
|
||||
protected ChatboxTextInput(ChatboxPanelManager chatboxPanelManager, ClientThread clientThread)
|
||||
{
|
||||
@@ -108,6 +129,16 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
|
||||
this.clientThread = clientThread;
|
||||
}
|
||||
|
||||
public ChatboxTextInput lines(int lines)
|
||||
{
|
||||
this.lines = lines;
|
||||
if (built)
|
||||
{
|
||||
clientThread.invoke(this::update);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChatboxTextInput prompt(String prompt)
|
||||
{
|
||||
this.prompt = prompt;
|
||||
@@ -157,7 +188,7 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
|
||||
end = v;
|
||||
}
|
||||
|
||||
this.cursor = start;
|
||||
this.cursorStart = start;
|
||||
this.cursorEnd = end;
|
||||
|
||||
if (built)
|
||||
@@ -209,7 +240,6 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
|
||||
|
||||
protected void update()
|
||||
{
|
||||
this.built = true;
|
||||
Widget container = chatboxPanelManager.getContainerWidget();
|
||||
container.deleteAllChildren();
|
||||
|
||||
@@ -232,103 +262,209 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
|
||||
|
||||
protected void buildEdit(int x, int y, int w, int h)
|
||||
{
|
||||
final List<Line> editLines = new ArrayList<>();
|
||||
|
||||
Widget container = chatboxPanelManager.getContainerWidget();
|
||||
|
||||
String lt = Text.escapeJagex(value.substring(0, this.cursor));
|
||||
String mt = Text.escapeJagex(value.substring(this.cursor, this.cursorEnd));
|
||||
String rt = Text.escapeJagex(value.substring(this.cursorEnd));
|
||||
|
||||
Widget leftText = container.createChild(-1, WidgetType.TEXT);
|
||||
Widget cursor = container.createChild(-1, WidgetType.RECTANGLE);
|
||||
Widget middleText = container.createChild(-1, WidgetType.TEXT);
|
||||
Widget rightText = container.createChild(-1, WidgetType.TEXT);
|
||||
|
||||
leftText.setFontId(fontID);
|
||||
FontTypeFace font = leftText.getFont();
|
||||
final Widget cursor = container.createChild(-1, WidgetType.RECTANGLE);
|
||||
long start = System.currentTimeMillis();
|
||||
cursor.setOnTimerListener((JavaScriptCallback) ev ->
|
||||
{
|
||||
boolean on = (System.currentTimeMillis() - start) % CURSOR_FLASH_RATE_MILLIS > (CURSOR_FLASH_RATE_MILLIS / 2);
|
||||
cursor.setOpacity(on ? 255 : 0);
|
||||
});
|
||||
cursor.setTextColor(0xFFFFFF);
|
||||
cursor.setHasListener(true);
|
||||
cursor.setFilled(true);
|
||||
cursor.setFontId(fontID);
|
||||
|
||||
FontTypeFace font = cursor.getFont();
|
||||
if (h <= 0)
|
||||
{
|
||||
h = font.getBaseline();
|
||||
}
|
||||
|
||||
int ltw = font.getTextWidth(lt);
|
||||
int mtw = font.getTextWidth(mt);
|
||||
int rtw = font.getTextWidth(rt);
|
||||
final int oy = y;
|
||||
final int ox = x;
|
||||
final int oh = h;
|
||||
|
||||
int fullWidth = ltw + mtw + rtw;
|
||||
|
||||
int ox = x;
|
||||
if (w > 0)
|
||||
int breakIndex = -1;
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < value.length(); i++)
|
||||
{
|
||||
x += (w - fullWidth) / 2;
|
||||
}
|
||||
|
||||
int ltx = x;
|
||||
int mtx = ltx + ltw;
|
||||
int rtx = mtx + mtw;
|
||||
|
||||
leftText.setText(lt);
|
||||
leftText.setOriginalX(ltx);
|
||||
leftText.setOriginalY(y);
|
||||
leftText.setOriginalWidth(ltw);
|
||||
leftText.setOriginalHeight(h);
|
||||
leftText.revalidate();
|
||||
|
||||
if (!mt.isEmpty())
|
||||
{
|
||||
cursor.setTextColor(0x113399);
|
||||
}
|
||||
else
|
||||
{
|
||||
cursor.setTextColor(0xFFFFFF);
|
||||
long start = System.currentTimeMillis();
|
||||
cursor.setOnTimerListener((JavaScriptCallback) ev ->
|
||||
int count = i - sb.length();
|
||||
final String c = value.charAt(i) + "";
|
||||
sb.append(c);
|
||||
if (BREAK_MATCHER.matcher(c).matches())
|
||||
{
|
||||
boolean on = (System.currentTimeMillis() - start) % CURSOR_FLASH_RATE_MILLIS > (CURSOR_FLASH_RATE_MILLIS / 2);
|
||||
cursor.setOpacity(on ? 255 : 0);
|
||||
});
|
||||
cursor.setHasListener(true);
|
||||
breakIndex = sb.length();
|
||||
}
|
||||
|
||||
if (i == value.length() - 1)
|
||||
{
|
||||
Line line = new Line(count, count + sb.length() - 1, sb.toString());
|
||||
editLines.add(line);
|
||||
break;
|
||||
}
|
||||
|
||||
if (font.getTextWidth(sb.toString() + value.charAt(i + 1)) < w)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (editLines.size() < this.lines - 1 || this.lines == 0)
|
||||
{
|
||||
if (breakIndex > 1)
|
||||
{
|
||||
String str = sb.substring(0, breakIndex);
|
||||
Line line = new Line(count, count + str.length() - 1, str);
|
||||
editLines.add(line);
|
||||
|
||||
sb.replace(0, breakIndex, "");
|
||||
breakIndex = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
Line line = new Line(count, count + sb.length() - 1, sb.toString());
|
||||
editLines.add(line);
|
||||
sb.replace(0, sb.length(), "");
|
||||
}
|
||||
}
|
||||
cursor.setFilled(true);
|
||||
cursor.setOriginalX(mtx - 1);
|
||||
cursor.setOriginalY(y);
|
||||
cursor.setOriginalWidth(2 + mtw);
|
||||
cursor.setOriginalHeight(h);
|
||||
cursor.revalidate();
|
||||
|
||||
middleText.setText(mt);
|
||||
middleText.setFontId(fontID);
|
||||
middleText.setOriginalX(mtx);
|
||||
middleText.setOriginalY(y);
|
||||
middleText.setOriginalWidth(mtw);
|
||||
middleText.setOriginalHeight(h);
|
||||
middleText.setTextColor(0xFFFFFF);
|
||||
middleText.revalidate();
|
||||
Rectangle bounds = new Rectangle(container.getCanvasLocation().getX() + container.getWidth(), y, 0, editLines.size() * oh);
|
||||
for (int i = 0; i < editLines.size() || i == 0; i++)
|
||||
{
|
||||
final Line line = editLines.size() > 0 ? editLines.get(i) : new Line(0, 0, "");
|
||||
final String text = line.text;
|
||||
final int len = text.length();
|
||||
|
||||
rightText.setText(rt);
|
||||
rightText.setFontId(fontID);
|
||||
rightText.setOriginalX(rtx);
|
||||
rightText.setOriginalY(y);
|
||||
rightText.setOriginalWidth(rtw);
|
||||
rightText.setOriginalHeight(h);
|
||||
rightText.revalidate();
|
||||
String lt = Text.escapeJagex(text);
|
||||
String mt = "";
|
||||
String rt = "";
|
||||
|
||||
final boolean isStartLine = cursorOnLine(cursorStart, line.start, line.end)
|
||||
|| (cursorOnLine(cursorStart, line.start, line.end + 1) && i == editLines.size() - 1);
|
||||
|
||||
final boolean isEndLine = cursorOnLine(cursorEnd, line.start, line.end);
|
||||
|
||||
if (isStartLine || isEndLine || (cursorEnd > line.end && cursorStart < line.start))
|
||||
{
|
||||
final int cIdx = Ints.constrainToRange(cursorStart - line.start, 0, len);
|
||||
final int ceIdx = Ints.constrainToRange(cursorEnd - line.start, 0, len);
|
||||
|
||||
lt = Text.escapeJagex(text.substring(0, cIdx));
|
||||
mt = Text.escapeJagex(text.substring(cIdx, ceIdx));
|
||||
rt = Text.escapeJagex(text.substring(ceIdx));
|
||||
}
|
||||
|
||||
final int ltw = font.getTextWidth(lt);
|
||||
final int mtw = font.getTextWidth(mt);
|
||||
final int rtw = font.getTextWidth(rt);
|
||||
final int fullWidth = ltw + mtw + rtw;
|
||||
|
||||
int ltx = ox;
|
||||
if (w > 0)
|
||||
{
|
||||
ltx += (w - fullWidth) / 2;
|
||||
}
|
||||
|
||||
final int mtx = ltx + ltw;
|
||||
final int rtx = mtx + mtw;
|
||||
|
||||
if (ltx < bounds.x)
|
||||
{
|
||||
bounds.setLocation(ltx, bounds.y);
|
||||
}
|
||||
|
||||
if (fullWidth > bounds.width)
|
||||
{
|
||||
bounds.setSize(fullWidth, bounds.height);
|
||||
}
|
||||
|
||||
if (editLines.size() == 0 || isStartLine)
|
||||
{
|
||||
cursor.setOriginalX(mtx - 1);
|
||||
cursor.setOriginalY(y);
|
||||
cursor.setOriginalWidth(2);
|
||||
cursor.setOriginalHeight(h);
|
||||
cursor.revalidate();
|
||||
}
|
||||
|
||||
if (!Strings.isNullOrEmpty(lt))
|
||||
{
|
||||
final Widget leftText = container.createChild(-1, WidgetType.TEXT);
|
||||
leftText.setFontId(fontID);
|
||||
leftText.setText(lt);
|
||||
leftText.setOriginalX(ltx);
|
||||
leftText.setOriginalY(y);
|
||||
leftText.setOriginalWidth(ltw);
|
||||
leftText.setOriginalHeight(h);
|
||||
leftText.revalidate();
|
||||
}
|
||||
|
||||
if (!Strings.isNullOrEmpty(mt))
|
||||
{
|
||||
final Widget background = container.createChild(-1, WidgetType.RECTANGLE);
|
||||
background.setTextColor(0x113399);
|
||||
background.setFilled(true);
|
||||
background.setOriginalX(mtx - 1);
|
||||
background.setOriginalY(y);
|
||||
background.setOriginalWidth(2 + mtw);
|
||||
background.setOriginalHeight(h);
|
||||
background.revalidate();
|
||||
|
||||
final Widget middleText = container.createChild(-1, WidgetType.TEXT);
|
||||
middleText.setText(mt);
|
||||
middleText.setFontId(fontID);
|
||||
middleText.setOriginalX(mtx);
|
||||
middleText.setOriginalY(y);
|
||||
middleText.setOriginalWidth(mtw);
|
||||
middleText.setOriginalHeight(h);
|
||||
middleText.setTextColor(0xFFFFFF);
|
||||
middleText.revalidate();
|
||||
}
|
||||
|
||||
if (!Strings.isNullOrEmpty(rt))
|
||||
{
|
||||
final Widget rightText = container.createChild(-1, WidgetType.TEXT);
|
||||
rightText.setText(rt);
|
||||
rightText.setFontId(fontID);
|
||||
rightText.setOriginalX(rtx);
|
||||
rightText.setOriginalY(y);
|
||||
rightText.setOriginalWidth(rtw);
|
||||
rightText.setOriginalHeight(h);
|
||||
rightText.revalidate();
|
||||
}
|
||||
|
||||
y += h;
|
||||
}
|
||||
|
||||
net.runelite.api.Point ccl = container.getCanvasLocation();
|
||||
int canvasX = ltx + ccl.getX();
|
||||
Rectangle bounds = new Rectangle(ccl.getX() + ox, ccl.getY() + y, w > 0 ? w : fullWidth, h);
|
||||
|
||||
String tsValue = value.toString();
|
||||
isInBounds = ev -> bounds.contains(ev.getPoint());
|
||||
getCharOffset = ev ->
|
||||
isInBounds = ev -> bounds.contains(new Point(ev.getX() - ccl.getX(), ev.getY() - ccl.getY()));
|
||||
getPointCharOffset = p ->
|
||||
{
|
||||
if (fullWidth <= 0)
|
||||
if (bounds.width <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cx = ev.getX() - canvasX;
|
||||
int cx = p.x - ccl.getX() - ox;
|
||||
int cy = p.y - ccl.getY() - oy;
|
||||
|
||||
int charIndex = (tsValue.length() * cx) / fullWidth;
|
||||
int currentLine = Ints.constrainToRange(cy / oh, 0, editLines.size() - 1);
|
||||
|
||||
final Line line = editLines.get(currentLine);
|
||||
final String tsValue = line.text;
|
||||
int charIndex = tsValue.length();
|
||||
int fullWidth = font.getTextWidth(tsValue);
|
||||
|
||||
int tx = ox;
|
||||
if (w > 0)
|
||||
{
|
||||
tx += (w - fullWidth) / 2;
|
||||
}
|
||||
cx -= tx;
|
||||
|
||||
// `i` is used to track max execution time incase there is a font with ligature width data that causes this to fail
|
||||
for (int i = tsValue.length(); i >= 0 && charIndex >= 0 && charIndex <= tsValue.length(); i--)
|
||||
@@ -353,22 +489,72 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
|
||||
break;
|
||||
}
|
||||
|
||||
if (charIndex < 0)
|
||||
charIndex = Ints.constrainToRange(charIndex, 0, tsValue.length());
|
||||
return line.start + charIndex;
|
||||
};
|
||||
|
||||
getLineOffset = code ->
|
||||
{
|
||||
if (editLines.size() < 2)
|
||||
{
|
||||
charIndex = 0;
|
||||
}
|
||||
if (charIndex > tsValue.length())
|
||||
{
|
||||
charIndex = tsValue.length();
|
||||
return cursorStart;
|
||||
}
|
||||
|
||||
return charIndex;
|
||||
int currentLine = -1;
|
||||
for (int i = 0; i < editLines.size(); i++)
|
||||
{
|
||||
Line l = editLines.get(i);
|
||||
if (cursorOnLine(cursorStart, l.start, l.end)
|
||||
|| (cursorOnLine(cursorStart, l.start, l.end + 1) && i == editLines.size() - 1))
|
||||
{
|
||||
currentLine = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentLine == -1
|
||||
|| (code == KeyEvent.VK_UP && currentLine == 0)
|
||||
|| (code == KeyEvent.VK_DOWN && currentLine == editLines.size() - 1))
|
||||
{
|
||||
return cursorStart;
|
||||
}
|
||||
|
||||
final Line line = editLines.get(currentLine);
|
||||
final int direction = code == KeyEvent.VK_UP ? -1 : 1;
|
||||
final Point dest = new Point(cursor.getCanvasLocation().getX(), cursor.getCanvasLocation().getY() + (direction * oh));
|
||||
final int charOffset = getPointCharOffset.applyAsInt(dest);
|
||||
|
||||
// Place cursor on right line if whitespace keep it on the same line or skip a line
|
||||
final Line nextLine = editLines.get(currentLine + direction);
|
||||
if ((direction == -1 && charOffset >= line.start)
|
||||
|| (direction == 1 && (charOffset > nextLine.end && (currentLine + direction != editLines.size() - 1))))
|
||||
{
|
||||
return nextLine.end;
|
||||
}
|
||||
|
||||
return charOffset;
|
||||
};
|
||||
}
|
||||
|
||||
private boolean cursorOnLine(final int cursor, final int start, final int end)
|
||||
{
|
||||
return (cursor >= start) && (cursor <= end);
|
||||
}
|
||||
|
||||
private int getCharOffset(MouseEvent ev)
|
||||
{
|
||||
if (getPointCharOffset == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return getPointCharOffset.applyAsInt(ev.getPoint());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void open()
|
||||
{
|
||||
this.built = true;
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -398,12 +584,12 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
|
||||
char c = e.getKeyChar();
|
||||
if (charValidator.test(c))
|
||||
{
|
||||
if (cursor != cursorEnd)
|
||||
if (cursorStart != cursorEnd)
|
||||
{
|
||||
value.delete(cursor, cursorEnd);
|
||||
value.delete(cursorStart, cursorEnd);
|
||||
}
|
||||
value.insert(cursor, c);
|
||||
cursorAt(cursor + 1);
|
||||
value.insert(cursorStart, c);
|
||||
cursorAt(cursorStart + 1);
|
||||
if (onChanged != null)
|
||||
{
|
||||
onChanged.accept(getValue());
|
||||
@@ -421,13 +607,13 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
|
||||
{
|
||||
case KeyEvent.VK_X:
|
||||
case KeyEvent.VK_C:
|
||||
if (cursor != cursorEnd)
|
||||
if (cursorStart != cursorEnd)
|
||||
{
|
||||
String s = value.substring(cursor, cursorEnd);
|
||||
String s = value.substring(cursorStart, cursorEnd);
|
||||
if (code == KeyEvent.VK_X)
|
||||
{
|
||||
value.delete(cursor, cursorEnd);
|
||||
cursorAt(cursor);
|
||||
value.delete(cursorStart, cursorEnd);
|
||||
cursorAt(cursorStart);
|
||||
}
|
||||
Toolkit.getDefaultToolkit()
|
||||
.getSystemClipboard()
|
||||
@@ -441,20 +627,20 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
|
||||
.getSystemClipboard()
|
||||
.getData(DataFlavor.stringFlavor)
|
||||
.toString();
|
||||
if (cursor != cursorEnd)
|
||||
if (cursorStart != cursorEnd)
|
||||
{
|
||||
value.delete(cursor, cursorEnd);
|
||||
value.delete(cursorStart, cursorEnd);
|
||||
}
|
||||
for (int i = 0; i < s.length(); i++)
|
||||
{
|
||||
char ch = s.charAt(i);
|
||||
if (charValidator.test(ch))
|
||||
{
|
||||
value.insert(cursor, ch);
|
||||
cursor++;
|
||||
value.insert(cursorStart, ch);
|
||||
cursorStart++;
|
||||
}
|
||||
}
|
||||
cursorAt(cursor);
|
||||
cursorAt(cursorStart);
|
||||
if (onChanged != null)
|
||||
{
|
||||
onChanged.accept(getValue());
|
||||
@@ -468,13 +654,13 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
|
||||
}
|
||||
return;
|
||||
}
|
||||
int newPos = cursor;
|
||||
int newPos = cursorStart;
|
||||
if (ev.isShiftDown())
|
||||
{
|
||||
if (selectionEnd == -1 || selectionStart == -1)
|
||||
{
|
||||
selectionStart = cursor;
|
||||
selectionEnd = cursor;
|
||||
selectionStart = cursorStart;
|
||||
selectionEnd = cursorStart;
|
||||
}
|
||||
newPos = selectionEnd;
|
||||
}
|
||||
@@ -486,20 +672,20 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
|
||||
switch (code)
|
||||
{
|
||||
case KeyEvent.VK_DELETE:
|
||||
if (cursor != cursorEnd)
|
||||
if (cursorStart != cursorEnd)
|
||||
{
|
||||
value.delete(cursor, cursorEnd);
|
||||
cursorAt(cursor);
|
||||
value.delete(cursorStart, cursorEnd);
|
||||
cursorAt(cursorStart);
|
||||
if (onChanged != null)
|
||||
{
|
||||
onChanged.accept(getValue());
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (cursor < value.length())
|
||||
if (cursorStart < value.length())
|
||||
{
|
||||
value.deleteCharAt(cursor);
|
||||
cursorAt(cursor);
|
||||
value.deleteCharAt(cursorStart);
|
||||
cursorAt(cursorStart);
|
||||
if (onChanged != null)
|
||||
{
|
||||
onChanged.accept(getValue());
|
||||
@@ -507,20 +693,20 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
|
||||
}
|
||||
return;
|
||||
case KeyEvent.VK_BACK_SPACE:
|
||||
if (cursor != cursorEnd)
|
||||
if (cursorStart != cursorEnd)
|
||||
{
|
||||
value.delete(cursor, cursorEnd);
|
||||
cursorAt(cursor);
|
||||
value.delete(cursorStart, cursorEnd);
|
||||
cursorAt(cursorStart);
|
||||
if (onChanged != null)
|
||||
{
|
||||
onChanged.accept(getValue());
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (cursor > 0)
|
||||
if (cursorStart > 0)
|
||||
{
|
||||
value.deleteCharAt(cursor - 1);
|
||||
cursorAt(cursor - 1);
|
||||
value.deleteCharAt(cursorStart - 1);
|
||||
cursorAt(cursorStart - 1);
|
||||
if (onChanged != null)
|
||||
{
|
||||
onChanged.accept(getValue());
|
||||
@@ -535,6 +721,14 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
|
||||
ev.consume();
|
||||
newPos++;
|
||||
break;
|
||||
case KeyEvent.VK_UP:
|
||||
ev.consume();
|
||||
newPos = getLineOffset.applyAsInt(code);
|
||||
break;
|
||||
case KeyEvent.VK_DOWN:
|
||||
ev.consume();
|
||||
newPos = getLineOffset.applyAsInt(code);
|
||||
break;
|
||||
case KeyEvent.VK_HOME:
|
||||
ev.consume();
|
||||
newPos = 0;
|
||||
@@ -553,9 +747,9 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
|
||||
return;
|
||||
case KeyEvent.VK_ESCAPE:
|
||||
ev.consume();
|
||||
if (cursor != cursorEnd)
|
||||
if (cursorStart != cursorEnd)
|
||||
{
|
||||
cursorAt(cursor);
|
||||
cursorAt(cursorStart);
|
||||
return;
|
||||
}
|
||||
chatboxPanelManager.close();
|
||||
@@ -602,16 +796,16 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
|
||||
}
|
||||
if (isInBounds == null || !isInBounds.test(mouseEvent))
|
||||
{
|
||||
if (cursor != cursorEnd)
|
||||
if (cursorStart != cursorEnd)
|
||||
{
|
||||
selectionStart = -1;
|
||||
selectionEnd = -1;
|
||||
cursorAt(getCharOffset.applyAsInt(mouseEvent));
|
||||
cursorAt(getCharOffset(mouseEvent));
|
||||
}
|
||||
return mouseEvent;
|
||||
}
|
||||
|
||||
int nco = getCharOffset.applyAsInt(mouseEvent);
|
||||
int nco = getCharOffset(mouseEvent);
|
||||
|
||||
if (mouseEvent.isShiftDown() && selectionEnd != -1)
|
||||
{
|
||||
@@ -653,7 +847,7 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
|
||||
return mouseEvent;
|
||||
}
|
||||
|
||||
int nco = getCharOffset.applyAsInt(mouseEvent);
|
||||
int nco = getCharOffset(mouseEvent);
|
||||
if (selectionStart != -1)
|
||||
{
|
||||
selectionEnd = nco;
|
||||
|
||||
@@ -36,6 +36,7 @@ import net.runelite.api.Client;
|
||||
import net.runelite.api.Point;
|
||||
import net.runelite.api.Tile;
|
||||
import net.runelite.api.coords.LocalPoint;
|
||||
import net.runelite.client.game.AgilityShortcut;
|
||||
import net.runelite.client.ui.overlay.Overlay;
|
||||
import net.runelite.client.ui.overlay.OverlayLayer;
|
||||
import net.runelite.client.ui.overlay.OverlayPosition;
|
||||
@@ -44,6 +45,7 @@ import net.runelite.client.ui.overlay.OverlayUtil;
|
||||
class AgilityOverlay extends Overlay
|
||||
{
|
||||
private static final int MAX_DISTANCE = 2350;
|
||||
private static final Color SHORTCUT_HIGH_LEVEL_COLOR = Color.ORANGE;
|
||||
|
||||
private final Client client;
|
||||
private final AgilityPlugin plugin;
|
||||
@@ -66,14 +68,15 @@ class AgilityOverlay extends Overlay
|
||||
LocalPoint playerLocation = client.getLocalPlayer().getLocalLocation();
|
||||
Point mousePosition = client.getMouseCanvasPosition();
|
||||
final List<Tile> marksOfGrace = plugin.getMarksOfGrace();
|
||||
plugin.getObstacles().forEach((object, tile) ->
|
||||
plugin.getObstacles().forEach((object, obstacle) ->
|
||||
{
|
||||
if (Obstacles.SHORTCUT_OBSTACLE_IDS.contains(object.getId()) && !config.highlightShortcuts() ||
|
||||
if (Obstacles.SHORTCUT_OBSTACLE_IDS.containsKey(object.getId()) && !config.highlightShortcuts() ||
|
||||
Obstacles.TRAP_OBSTACLE_IDS.contains(object.getId()) && !config.showTrapOverlay())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Tile tile = obstacle.getTile();
|
||||
if (tile.getPlane() == client.getPlane()
|
||||
&& object.getLocalLocation().distanceTo(playerLocation) < MAX_DISTANCE)
|
||||
{
|
||||
@@ -87,11 +90,11 @@ class AgilityOverlay extends Overlay
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Area objectClickbox = object.getClickbox();
|
||||
if (objectClickbox != null)
|
||||
{
|
||||
Color configColor = config.getOverlayColor();
|
||||
AgilityShortcut agilityShortcut = obstacle.getShortcut();
|
||||
Color configColor = agilityShortcut == null || agilityShortcut.getLevel() <= plugin.getAgilityLevel() ? config.getOverlayColor() : SHORTCUT_HIGH_LEVEL_COLOR;
|
||||
if (config.highlightMarks() && !marksOfGrace.isEmpty())
|
||||
{
|
||||
configColor = config.getMarkColor();
|
||||
|
||||
@@ -38,10 +38,12 @@ import net.runelite.api.Item;
|
||||
import net.runelite.api.ItemID;
|
||||
import static net.runelite.api.ItemID.AGILITY_ARENA_TICKET;
|
||||
import net.runelite.api.Player;
|
||||
import net.runelite.api.Skill;
|
||||
import static net.runelite.api.Skill.AGILITY;
|
||||
import net.runelite.api.Tile;
|
||||
import net.runelite.api.TileObject;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
import net.runelite.api.events.BoostedLevelChanged;
|
||||
import net.runelite.api.events.ConfigChanged;
|
||||
import net.runelite.api.events.DecorativeObjectChanged;
|
||||
import net.runelite.api.events.DecorativeObjectDespawned;
|
||||
@@ -63,6 +65,7 @@ import net.runelite.api.events.WallObjectSpawned;
|
||||
import net.runelite.client.Notifier;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
import net.runelite.client.game.AgilityShortcut;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.plugins.PluginDescriptor;
|
||||
@@ -80,7 +83,7 @@ public class AgilityPlugin extends Plugin
|
||||
private static final int AGILITY_ARENA_REGION_ID = 11157;
|
||||
|
||||
@Getter
|
||||
private final Map<TileObject, Tile> obstacles = new HashMap<>();
|
||||
private final Map<TileObject, Obstacle> obstacles = new HashMap<>();
|
||||
|
||||
@Getter
|
||||
private final List<Tile> marksOfGrace = new ArrayList<>();
|
||||
@@ -115,6 +118,9 @@ public class AgilityPlugin extends Plugin
|
||||
private int lastAgilityXp;
|
||||
private WorldPoint lastArenaTicketPosition;
|
||||
|
||||
@Getter
|
||||
private int agilityLevel;
|
||||
|
||||
@Provides
|
||||
AgilityConfig getConfig(ConfigManager configManager)
|
||||
{
|
||||
@@ -126,6 +132,7 @@ public class AgilityPlugin extends Plugin
|
||||
{
|
||||
overlayManager.add(agilityOverlay);
|
||||
overlayManager.add(lapCounterOverlay);
|
||||
agilityLevel = client.getBoostedSkillLevel(Skill.AGILITY);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -136,6 +143,7 @@ public class AgilityPlugin extends Plugin
|
||||
marksOfGrace.clear();
|
||||
obstacles.clear();
|
||||
session = null;
|
||||
agilityLevel = 0;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
@@ -208,6 +216,17 @@ public class AgilityPlugin extends Plugin
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Subscribe
|
||||
public void onBoostedLevelChanged(BoostedLevelChanged boostedLevelChanged)
|
||||
{
|
||||
Skill skill = boostedLevelChanged.getSkill();
|
||||
if (skill == AGILITY)
|
||||
{
|
||||
agilityLevel = client.getBoostedSkillLevel(skill);
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onItemSpawned(ItemSpawned itemSpawned)
|
||||
{
|
||||
@@ -366,11 +385,40 @@ public class AgilityPlugin extends Plugin
|
||||
}
|
||||
|
||||
if (Obstacles.COURSE_OBSTACLE_IDS.contains(newObject.getId()) ||
|
||||
Obstacles.SHORTCUT_OBSTACLE_IDS.contains(newObject.getId()) ||
|
||||
(Obstacles.TRAP_OBSTACLE_IDS.contains(newObject.getId())
|
||||
&& Obstacles.TRAP_OBSTACLE_REGIONS.contains(newObject.getWorldLocation().getRegionID())))
|
||||
{
|
||||
obstacles.put(newObject, tile);
|
||||
obstacles.put(newObject, new Obstacle(tile, null));
|
||||
}
|
||||
|
||||
if (Obstacles.SHORTCUT_OBSTACLE_IDS.containsKey(newObject.getId()))
|
||||
{
|
||||
AgilityShortcut closestShortcut = null;
|
||||
int distance = -1;
|
||||
|
||||
// Find the closest shortcut to this object
|
||||
for (AgilityShortcut shortcut : Obstacles.SHORTCUT_OBSTACLE_IDS.get(newObject.getId()))
|
||||
{
|
||||
if (shortcut.getWorldLocation() == null)
|
||||
{
|
||||
closestShortcut = shortcut;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
int newDistance = shortcut.getWorldLocation().distanceTo2D(newObject.getWorldLocation());
|
||||
if (closestShortcut == null || newDistance < distance)
|
||||
{
|
||||
closestShortcut = shortcut;
|
||||
distance = newDistance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (closestShortcut != null)
|
||||
{
|
||||
obstacles.put(newObject, new Obstacle(tile, closestShortcut));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2019, MrGroggle
|
||||
* 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 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.client.plugins.agility;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Value;
|
||||
import net.runelite.api.Tile;
|
||||
import net.runelite.client.game.AgilityShortcut;
|
||||
|
||||
@Value
|
||||
@AllArgsConstructor
|
||||
class Obstacle
|
||||
{
|
||||
private final Tile tile;
|
||||
@Nullable
|
||||
private final AgilityShortcut shortcut;
|
||||
}
|
||||
@@ -25,11 +25,27 @@
|
||||
package net.runelite.client.plugins.agility;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Multimap;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import static net.runelite.api.NullObjectID.*;
|
||||
import static net.runelite.api.NullObjectID.NULL_10872;
|
||||
import static net.runelite.api.NullObjectID.NULL_10873;
|
||||
import static net.runelite.api.NullObjectID.NULL_12945;
|
||||
import static net.runelite.api.NullObjectID.NULL_18083;
|
||||
import static net.runelite.api.NullObjectID.NULL_18116;
|
||||
import static net.runelite.api.NullObjectID.NULL_18122;
|
||||
import static net.runelite.api.NullObjectID.NULL_18124;
|
||||
import static net.runelite.api.NullObjectID.NULL_18129;
|
||||
import static net.runelite.api.NullObjectID.NULL_18130;
|
||||
import static net.runelite.api.NullObjectID.NULL_18132;
|
||||
import static net.runelite.api.NullObjectID.NULL_18133;
|
||||
import static net.runelite.api.NullObjectID.NULL_18135;
|
||||
import static net.runelite.api.NullObjectID.NULL_18136;
|
||||
import static net.runelite.api.NullObjectID.NULL_3550;
|
||||
import static net.runelite.api.ObjectID.*;
|
||||
import net.runelite.client.game.AgilityShortcut;
|
||||
|
||||
class Obstacles
|
||||
{
|
||||
@@ -62,7 +78,7 @@ class Obstacles
|
||||
STEPPING_STONE_15412, TROPICAL_TREE_15414, MONKEYBARS_15417, SKULL_SLOPE_15483, ROPE_15487, TROPICAL_TREE_16062,
|
||||
// Falador
|
||||
ROUGH_WALL_10833, TIGHTROPE_10834, HAND_HOLDS_10836, GAP_11161, GAP_11360, TIGHTROPE_11361,
|
||||
TIGHTROPE_11364, GAP_11365, LEDGE_11366, LEDGE_11367, LEDGE_11368, LEDGE_11370, EDGE_11371,
|
||||
TIGHTROPE_11364, GAP_11365, LEDGE_11366, LEDGE_11367, LEDGE_11369, LEDGE_11370, EDGE_11371,
|
||||
// Wilderness
|
||||
OBSTACLE_PIPE_23137, ROPESWING_23132, STEPPING_STONE_23556, LOG_BALANCE_23542, ROCKS_23640,
|
||||
// Seers
|
||||
@@ -91,144 +107,7 @@ class Obstacles
|
||||
ZIP_LINE_11645, ZIP_LINE_11646
|
||||
);
|
||||
|
||||
static final Set<Integer> SHORTCUT_OBSTACLE_IDS = ImmutableSet.of(
|
||||
// Grand Exchange
|
||||
UNDERWALL_TUNNEL_16529, UNDERWALL_TUNNEL_16530,
|
||||
// South Varrock
|
||||
STEPPING_STONE_16533, FENCE_16518, ROCKS_16549, ROCKS_16550,
|
||||
// Falador
|
||||
WALL_17049, WALL_17050, CRUMBLING_WALL_24222, UNDERWALL_TUNNEL, UNDERWALL_TUNNEL_16528, CREVICE_16543,
|
||||
// Draynor
|
||||
UNDERWALL_TUNNEL_19032, UNDERWALL_TUNNEL_19036,
|
||||
// South Lumbridge
|
||||
BROKEN_RAFT, STEPPING_STONE_16513,
|
||||
// Trollheim
|
||||
ROCKS_3790, ROCKS_3791, ROCKS_3803, ROCKS_3804, ROCKS_16523, ROCKS_16524, ROCKS_3748, ROCKS_16545, ROCKS_16521,
|
||||
ROCKS_16522, ROCKS_16464,
|
||||
// North Camelot
|
||||
LOG_BALANCE_16540, LOG_BALANCE_16541, LOG_BALANCE_16542,
|
||||
// Rellekka
|
||||
BROKEN_FENCE,
|
||||
// Ardougne
|
||||
LOG_BALANCE_16546, LOG_BALANCE_16547, LOG_BALANCE_16548,
|
||||
// Yanille
|
||||
CASTLE_WALL, HOLE_16520, WALL_17047,
|
||||
// Observatory
|
||||
NULL_31849,
|
||||
// Gnome Stronghold
|
||||
ROCKS_16534, ROCKS_16535,
|
||||
// Karamja Volcano
|
||||
STRONG_TREE_17074,
|
||||
// Shilo Village
|
||||
STEPPING_STONE_16466,
|
||||
// Vine east of Shilo Village
|
||||
NULL_26884, NULL_26886,
|
||||
// Stepping stones east of Shilo Village
|
||||
STEPPING_STONES, STEPPING_STONES_23646, STEPPING_STONES_23647,
|
||||
// Middle of Karamja
|
||||
A_WOODEN_LOG,
|
||||
// Slayer Tower
|
||||
SPIKEY_CHAIN, SPIKEY_CHAIN_16538,
|
||||
// Fremennik Slayer Cave
|
||||
STRANGE_FLOOR_16544, CREVICE_16539, STEPS_29993,
|
||||
// Wilderness
|
||||
STEPPING_STONE_14918, STEPPING_STONE_14917, ROCKY_HANDHOLDS_26404, ROCKY_HANDHOLDS_26405, ROCKY_HANDHOLDS_26406,
|
||||
// Godwars
|
||||
ROCKY_HANDHOLDS_26400, ROCKY_HANDHOLDS_26401, ROCKY_HANDHOLDS_26402,
|
||||
// Seers' Village Coal Mine
|
||||
LOG_BALANCE_23274,
|
||||
// Arceuus Essence Mine
|
||||
ROCKS_27984, ROCKS_27985, BOULDER_27990, ROCKS_27987, ROCKS_27988,
|
||||
// Wintertodt
|
||||
GAP_29326,
|
||||
// Gnome Stronghold Slayer Underground
|
||||
TUNNEL_30174, TUNNEL_30175,
|
||||
// Taverley Underground
|
||||
OBSTACLE_PIPE_16509, STRANGE_FLOOR, ROCKS, ROCKS_14106, LOOSE_RAILING_28849,
|
||||
// Heroes Guild
|
||||
CREVICE_9739, CREVICE_9740,
|
||||
// Fossil Island
|
||||
HOLE_31481, HOLE_31482, LADDER_30938, LADDER_30939, LADDER_30940, LADDER_30941, ROPE_ANCHOR, ROPE_ANCHOR_30917,
|
||||
RUBBER_CAP_MUSHROOM,
|
||||
ROCKS_31757, ROCKS_31758, ROCKS_31759, PILLAR_31809,
|
||||
// West Brimhaven
|
||||
ROPESWING_23568, ROPESWING_23569,
|
||||
// Brimhaven Dungeon
|
||||
VINE_26880, VINE_26882, PIPE_21728, STEPPING_STONE_19040, PIPE_21727, LOG_BALANCE_20882, LOG_BALANCE_20884,
|
||||
STEPPING_STONE_21738, STEPPING_STONE_21739, TIGHTGAP,
|
||||
// Lumbridge
|
||||
STILE_12982,
|
||||
// Edgeville Dungeon
|
||||
MONKEYBARS_23566, OBSTACLE_PIPE_16511,
|
||||
// Miscellania
|
||||
STEPPING_STONE_11768,
|
||||
// Kalphite
|
||||
CREVICE_16465,
|
||||
// Eagles' Peak
|
||||
ROCKS_19849,
|
||||
// Catherby
|
||||
CROSSBOW_TREE_17062, ROCKS_17042,
|
||||
// McGrubor's Woods
|
||||
LOOSE_RAILING,
|
||||
// Cairn Isle
|
||||
ROCKS_2231,
|
||||
// South Kourend
|
||||
STEPPING_STONE_29728, STEPPING_STONE_29729, STEPPING_STONE_29730,
|
||||
// Cosmic Temple
|
||||
JUTTING_WALL_17002,
|
||||
// Arandar
|
||||
ROCKS_16514, ROCKS_16515, LOG_BALANCE_3933,
|
||||
// South River Salve
|
||||
STEPPING_STONE_13504,
|
||||
DARK_TUNNEL_10047,
|
||||
// Ectofuntus
|
||||
WEATHERED_WALL, WEATHERED_WALL_16526,
|
||||
// Mos Le'Harmless
|
||||
STEPPING_STONE_19042,
|
||||
// North River Salve
|
||||
ROCKS_16998, ROCKS_16999, ORNATE_RAILING, ORNATE_RAILING_17000,
|
||||
// West Zul-Andra
|
||||
STEPPING_STONE_10663,
|
||||
// Yanille Agility Dungeon
|
||||
BALANCING_LEDGE_23548, OBSTACLE_PIPE_23140, MONKEYBARS_23567, PILE_OF_RUBBLE_23563, PILE_OF_RUBBLE_23564,
|
||||
// High Level Wilderness Dungeon
|
||||
CREVICE_19043,
|
||||
// Revenant Caves
|
||||
PILLAR_31561,
|
||||
// Elf Camp Isafdar Tirranwn
|
||||
LOG_BALANCE_3931, LOG_BALANCE_3930, LOG_BALANCE_3929, LOG_BALANCE_3932, DENSE_FOREST_3938, DENSE_FOREST_3939,
|
||||
DENSE_FOREST_3998, DENSE_FOREST_3999, DENSE_FOREST, LEAVES, LEAVES_3924, LEAVES_3925, STICKS, TRIPWIRE,
|
||||
// Gu'Tanoth bridge
|
||||
GAP, GAP_2831,
|
||||
// Lumbridge Swamp Caves
|
||||
STEPPING_STONE_5948, STEPPING_STONE_5949, ROCKS_6673,
|
||||
// Morytania Pirate Ship
|
||||
ROCK_16115,
|
||||
// Agility Pyramid Entrance
|
||||
CLIMBING_ROCKS_11948, CLIMBING_ROCKS_11949,
|
||||
// Lumber Yard
|
||||
BROKEN_FENCE_2618,
|
||||
// Ungael and Vorkath crater
|
||||
NULL_25337, NULL_29868, NULL_29869, NULL_29870, ICE_CHUNKS_31822, NULL_31823, ICE_CHUNKS_31990,
|
||||
// Underwater Area Fossil Island
|
||||
TUNNEL_30959, HOLE_30966, OBSTACLE, OBSTACLE_30767, OBSTACLE_30964, OBSTACLE_30962,
|
||||
// Tree Gnome Village
|
||||
LOOSE_RAILING_2186,
|
||||
// Weiss
|
||||
LITTLE_BOULDER, ROCKSLIDE_33184, ROCKSLIDE_33185, NULL_33327, NULL_33328, LEDGE_33190, ROCKSLIDE_33191, FALLEN_TREE_33192,
|
||||
// Al-Kharid
|
||||
BROKEN_WALL_33344, BIG_WINDOW,
|
||||
// Burgh de Rott
|
||||
LOW_FENCE,
|
||||
// Taverley
|
||||
STILE,
|
||||
// Asgarnian Ice Dungeon
|
||||
STEPS,
|
||||
// Fossil Island Wyvern Cave
|
||||
STAIRS_31485,
|
||||
// Mount Karuulm
|
||||
ROCKS_34397, ROCKS_34396
|
||||
);
|
||||
static final Multimap<Integer, AgilityShortcut> SHORTCUT_OBSTACLE_IDS;
|
||||
|
||||
static final Set<Integer> TRAP_OBSTACLE_IDS = ImmutableSet.of(
|
||||
// Agility pyramid
|
||||
@@ -236,4 +115,17 @@ class Obstacles
|
||||
);
|
||||
|
||||
static final List<Integer> TRAP_OBSTACLE_REGIONS = ImmutableList.of(12105, 13356);
|
||||
|
||||
static
|
||||
{
|
||||
final ImmutableMultimap.Builder<Integer, AgilityShortcut> builder = ImmutableMultimap.builder();
|
||||
for (final AgilityShortcut item : AgilityShortcut.values())
|
||||
{
|
||||
for (int obstacle : item.getObstacleIds())
|
||||
{
|
||||
builder.put(obstacle, item);
|
||||
}
|
||||
}
|
||||
SHORTCUT_OBSTACLE_IDS = builder.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@ import net.runelite.client.callback.ClientThread;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.game.SpriteManager;
|
||||
import net.runelite.client.game.chatbox.ChatboxPanelManager;
|
||||
import net.runelite.client.input.KeyListener;
|
||||
import net.runelite.client.input.KeyManager;
|
||||
@@ -125,6 +126,9 @@ public class BankTagsPlugin extends Plugin implements MouseWheelListener, KeyLis
|
||||
@Inject
|
||||
private KeyManager keyManager;
|
||||
|
||||
@Inject
|
||||
private SpriteManager spriteManager;
|
||||
|
||||
private boolean shiftPressed = false;
|
||||
|
||||
@Provides
|
||||
@@ -139,7 +143,7 @@ public class BankTagsPlugin extends Plugin implements MouseWheelListener, KeyLis
|
||||
keyManager.registerKeyListener(this);
|
||||
mouseManager.registerMouseWheelListener(this);
|
||||
clientThread.invokeLater(tabInterface::init);
|
||||
client.getSpriteOverrides().putAll(TabSprites.toMap(client));
|
||||
spriteManager.addSpriteOverrides(TabSprites.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -148,11 +152,7 @@ public class BankTagsPlugin extends Plugin implements MouseWheelListener, KeyLis
|
||||
keyManager.unregisterKeyListener(this);
|
||||
mouseManager.unregisterMouseWheelListener(this);
|
||||
clientThread.invokeLater(tabInterface::destroy);
|
||||
|
||||
for (TabSprites value : TabSprites.values())
|
||||
{
|
||||
client.getSpriteOverrides().remove(value.getSpriteId());
|
||||
}
|
||||
spriteManager.removeSpriteOverrides(TabSprites.values());
|
||||
|
||||
shiftPressed = false;
|
||||
}
|
||||
|
||||
@@ -167,6 +167,20 @@ public class TagManager
|
||||
}
|
||||
}
|
||||
|
||||
public void renameTag(String oldTag, String newTag)
|
||||
{
|
||||
List<Integer> items = getItemsForTag(Text.standardize(oldTag));
|
||||
items.forEach(id ->
|
||||
{
|
||||
Collection<String> tags = getTags(id, id < 0);
|
||||
|
||||
tags.remove(Text.standardize(oldTag));
|
||||
tags.add(Text.standardize(newTag));
|
||||
|
||||
setTags(id, tags, id < 0);
|
||||
});
|
||||
}
|
||||
|
||||
private int getItemId(int itemId, boolean variation)
|
||||
{
|
||||
itemId = Math.abs(itemId);
|
||||
|
||||
@@ -39,5 +39,6 @@ class MenuIndexes
|
||||
static final int CHANGE_ICON = 3;
|
||||
static final int DELETE_TAB = 4;
|
||||
static final int EXPORT_TAB = 5;
|
||||
static final int RENAME_TAB = 6;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,6 @@ import net.runelite.api.SpriteID;
|
||||
import net.runelite.api.VarClientInt;
|
||||
import net.runelite.api.VarClientStr;
|
||||
import net.runelite.api.Varbits;
|
||||
import net.runelite.api.widgets.WidgetType;
|
||||
import net.runelite.api.events.MenuEntryAdded;
|
||||
import net.runelite.api.events.MenuOptionClicked;
|
||||
import net.runelite.api.vars.InputType;
|
||||
@@ -73,15 +72,14 @@ import net.runelite.api.widgets.JavaScriptCallback;
|
||||
import net.runelite.api.widgets.Widget;
|
||||
import net.runelite.api.widgets.WidgetConfig;
|
||||
import net.runelite.api.widgets.WidgetInfo;
|
||||
import net.runelite.api.widgets.WidgetSizeMode;
|
||||
import net.runelite.api.widgets.WidgetType;
|
||||
import net.runelite.client.Notifier;
|
||||
import net.runelite.client.callback.ClientThread;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.game.chatbox.ChatboxPanelManager;
|
||||
import net.runelite.client.plugins.banktags.BankTagsConfig;
|
||||
import net.runelite.client.plugins.banktags.BankTagsPlugin;
|
||||
import static net.runelite.client.plugins.banktags.BankTagsPlugin.CONFIG_GROUP;
|
||||
import static net.runelite.client.plugins.banktags.BankTagsPlugin.ICON_SEARCH;
|
||||
import static net.runelite.client.plugins.banktags.BankTagsPlugin.TAG_SEARCH;
|
||||
import static net.runelite.client.plugins.banktags.BankTagsPlugin.VAR_TAG_SUFFIX;
|
||||
import net.runelite.client.plugins.banktags.TagManager;
|
||||
@@ -102,6 +100,7 @@ public class TabInterface
|
||||
private static final String EXPORT_TAB = "Export tag tab";
|
||||
private static final String IMPORT_TAB = "Import tag tab";
|
||||
private static final String VIEW_TAB = "View tag tab";
|
||||
private static final String RENAME_TAB = "Rename tag tab";
|
||||
private static final String CHANGE_ICON = "Change icon";
|
||||
private static final String REMOVE_TAG = "Remove-tag";
|
||||
private static final String TAG_GEAR = "Tag-equipment";
|
||||
@@ -111,11 +110,12 @@ public class TabInterface
|
||||
private static final int BUTTON_HEIGHT = 20;
|
||||
private static final int MARGIN = 1;
|
||||
private static final int SCROLL_TICK = 500;
|
||||
private static final int INCINERATOR_WIDTH = 48;
|
||||
private static final int INCINERATOR_HEIGHT = 39;
|
||||
|
||||
private final Client client;
|
||||
private final ClientThread clientThread;
|
||||
private final ItemManager itemManager;
|
||||
private final ConfigManager configManager;
|
||||
private final TagManager tagManager;
|
||||
private final TabManager tabManager;
|
||||
private final ChatboxPanelManager chatboxPanelManager;
|
||||
@@ -148,7 +148,6 @@ public class TabInterface
|
||||
final Client client,
|
||||
final ClientThread clientThread,
|
||||
final ItemManager itemManager,
|
||||
final ConfigManager configManager,
|
||||
final TagManager tagManager,
|
||||
final TabManager tabManager,
|
||||
final ChatboxPanelManager chatboxPanelManager,
|
||||
@@ -159,7 +158,6 @@ public class TabInterface
|
||||
this.client = client;
|
||||
this.clientThread = clientThread;
|
||||
this.itemManager = itemManager;
|
||||
this.configManager = configManager;
|
||||
this.tagManager = tagManager;
|
||||
this.tabManager = tabManager;
|
||||
this.chatboxPanelManager = chatboxPanelManager;
|
||||
@@ -211,7 +209,7 @@ public class TabInterface
|
||||
|
||||
if (config.rememberTab() && !Strings.isNullOrEmpty(config.tab()))
|
||||
{
|
||||
openTag(TAG_SEARCH + config.tab());
|
||||
openTag(config.tab());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,7 +237,7 @@ public class TabInterface
|
||||
tagManager.addTag(item, activeTab.getTag(), false);
|
||||
}
|
||||
|
||||
openTag(TAG_SEARCH + activeTab.getTag());
|
||||
openTag(activeTab.getTag());
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -292,7 +290,7 @@ public class TabInterface
|
||||
final Iterator<String> dataIter = Text.fromCSV(dataString).iterator();
|
||||
final String name = dataIter.next();
|
||||
final String icon = dataIter.next();
|
||||
configManager.setConfiguration(CONFIG_GROUP, ICON_SEARCH + name, icon);
|
||||
tabManager.setIcon(name, icon);
|
||||
|
||||
while (dataIter.hasNext())
|
||||
{
|
||||
@@ -306,7 +304,7 @@ public class TabInterface
|
||||
|
||||
if (activeTab != null && name.equals(activeTab.getTag()))
|
||||
{
|
||||
openTag(TAG_SEARCH + activeTab.getTag());
|
||||
openTag(activeTab.getTag());
|
||||
}
|
||||
|
||||
notifier.notify("Tag tab " + name + " has been imported from your clipboard!");
|
||||
@@ -336,7 +334,7 @@ public class TabInterface
|
||||
}
|
||||
else
|
||||
{
|
||||
openTag(TAG_SEARCH + Text.removeTags(clicked.getName()));
|
||||
openTag(Text.removeTags(clicked.getName()));
|
||||
}
|
||||
|
||||
client.playSoundEffect(SoundEffectID.UI_BOOP);
|
||||
@@ -373,6 +371,10 @@ public class TabInterface
|
||||
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(stringSelection, null);
|
||||
notifier.notify("Tag tab " + tagTab.getTag() + " has been copied to your clipboard!");
|
||||
break;
|
||||
case Tab.RENAME_TAB:
|
||||
String renameTarget = Text.standardize(event.getOpbase());
|
||||
renameTab(renameTarget);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -550,7 +552,7 @@ public class TabInterface
|
||||
int itemId = itemManager.canonicalize(item.getId());
|
||||
iconToSet.setIconItemId(itemId);
|
||||
iconToSet.getIcon().setItemId(itemId);
|
||||
configManager.setConfiguration(CONFIG_GROUP, ICON_SEARCH + iconToSet.getTag(), itemId + "");
|
||||
tabManager.setIcon(iconToSet.getTag(), itemId + "");
|
||||
event.consume();
|
||||
}
|
||||
|
||||
@@ -597,7 +599,7 @@ public class TabInterface
|
||||
{
|
||||
if (activeTab != null && tags.contains(activeTab.getTag()))
|
||||
{
|
||||
openTag(TAG_SEARCH + activeTab.getTag());
|
||||
openTag(activeTab.getTag());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -683,6 +685,7 @@ public class TabInterface
|
||||
btn.setAction(2, CHANGE_ICON);
|
||||
btn.setAction(3, REMOVE_TAB);
|
||||
btn.setAction(4, EXPORT_TAB);
|
||||
btn.setAction(5, RENAME_TAB);
|
||||
btn.setOnOpListener((JavaScriptCallback) this::handleTagTab);
|
||||
tagTab.setBackground(btn);
|
||||
}
|
||||
@@ -712,13 +715,66 @@ public class TabInterface
|
||||
}
|
||||
|
||||
tabManager.remove(tag);
|
||||
configManager.unsetConfiguration(CONFIG_GROUP, ICON_SEARCH + tag);
|
||||
tabManager.save();
|
||||
|
||||
updateBounds();
|
||||
scrollTab(0);
|
||||
}
|
||||
|
||||
private void renameTab(String oldTag)
|
||||
{
|
||||
chatboxPanelManager.openTextInput("Enter new tag name for tag \"" + oldTag + "\":")
|
||||
.onDone((newTag) -> clientThread.invoke(() ->
|
||||
{
|
||||
if (!Strings.isNullOrEmpty(newTag) && !newTag.equalsIgnoreCase(oldTag))
|
||||
{
|
||||
if (tabManager.find(newTag) == null)
|
||||
{
|
||||
TagTab tagTab = tabManager.find(oldTag);
|
||||
tagTab.setTag(newTag);
|
||||
|
||||
final String coloredName = ColorUtil.wrapWithColorTag(newTag, HILIGHT_COLOR);
|
||||
tagTab.getIcon().setName(coloredName);
|
||||
tagTab.getBackground().setName(coloredName);
|
||||
|
||||
tabManager.removeIcon(oldTag);
|
||||
tabManager.setIcon(newTag, tagTab.getIconItemId() + "");
|
||||
|
||||
tabManager.save();
|
||||
tagManager.renameTag(oldTag, newTag);
|
||||
|
||||
if (activeTab != null && activeTab.equals(tagTab))
|
||||
{
|
||||
openTag(newTag);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
chatboxPanelManager.openTextMenuInput("The specified bank tag already exists.")
|
||||
.option("1. Merge into existing tag \"" + newTag + "\".", () ->
|
||||
clientThread.invoke(() ->
|
||||
{
|
||||
tagManager.renameTag(oldTag, newTag);
|
||||
final String activeTag = activeTab != null ? activeTab.getTag() : "";
|
||||
deleteTab(oldTag);
|
||||
|
||||
if (activeTag.equals(oldTag))
|
||||
{
|
||||
openTag(newTag);
|
||||
}
|
||||
})
|
||||
)
|
||||
.option("2. Choose a different name.", () ->
|
||||
clientThread.invoke(() ->
|
||||
renameTab(oldTag))
|
||||
)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}))
|
||||
.build();
|
||||
}
|
||||
|
||||
private void scrollTick(int direction)
|
||||
{
|
||||
// This ensures that dragging on scroll buttons do not scrolls too fast
|
||||
@@ -805,17 +861,18 @@ public class TabInterface
|
||||
|
||||
if (incinerator != null && !incinerator.isHidden())
|
||||
{
|
||||
// This is the required way to move incinerator, don't change it!
|
||||
incinerator.setOriginalHeight(39);
|
||||
incinerator.setOriginalWidth(48);
|
||||
incinerator.setRelativeY(itemContainer.getHeight());
|
||||
incinerator.revalidate();
|
||||
incinerator.setOriginalHeight(INCINERATOR_HEIGHT);
|
||||
incinerator.setOriginalWidth(INCINERATOR_WIDTH);
|
||||
incinerator.setOriginalY(INCINERATOR_HEIGHT);
|
||||
|
||||
Widget child = incinerator.getDynamicChildren()[0];
|
||||
child.setHeight(39);
|
||||
child.setWidth(48);
|
||||
child.setOriginalHeight(INCINERATOR_HEIGHT);
|
||||
child.setOriginalWidth(INCINERATOR_WIDTH);
|
||||
child.setWidthMode(WidgetSizeMode.ABSOLUTE);
|
||||
child.setHeightMode(WidgetSizeMode.ABSOLUTE);
|
||||
child.setType(WidgetType.GRAPHIC);
|
||||
child.setSpriteId(TabSprites.INCINERATOR.getSpriteId());
|
||||
incinerator.revalidate();
|
||||
|
||||
bounds.setSize(TAB_WIDTH + MARGIN * 2, height - incinerator.getHeight());
|
||||
}
|
||||
@@ -900,7 +957,6 @@ public class TabInterface
|
||||
private void updateWidget(Widget t, int y)
|
||||
{
|
||||
t.setOriginalY(y);
|
||||
t.setRelativeY(y);
|
||||
t.setHidden(y < (bounds.y + BUTTON_HEIGHT + MARGIN) || y > (bounds.y + bounds.height - TAB_HEIGHT - MARGIN - BUTTON_HEIGHT));
|
||||
t.revalidate();
|
||||
}
|
||||
@@ -913,10 +969,10 @@ public class TabInterface
|
||||
return itemManager.getItemComposition(item.getId());
|
||||
}
|
||||
|
||||
private void openTag(String tag)
|
||||
private void openTag(final String tag)
|
||||
{
|
||||
bankSearch.search(InputType.SEARCH, tag, true);
|
||||
activateTab(tabManager.find(tag.substring(TAG_SEARCH.length())));
|
||||
bankSearch.search(InputType.SEARCH, TAG_SEARCH + tag, true);
|
||||
activateTab(tabManager.find(tag));
|
||||
|
||||
// When tab is selected with search window open, the search window closes but the search button
|
||||
// stays highlighted, this solves that issue
|
||||
|
||||
@@ -115,6 +115,7 @@ class TabManager
|
||||
{
|
||||
tagTab.setHidden(true);
|
||||
tabs.remove(tagTab);
|
||||
removeIcon(tag);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,6 +125,16 @@ class TabManager
|
||||
configManager.setConfiguration(CONFIG_GROUP, TAG_TABS_CONFIG, tags);
|
||||
}
|
||||
|
||||
void removeIcon(final String tag)
|
||||
{
|
||||
configManager.unsetConfiguration(CONFIG_GROUP, ICON_SEARCH + Text.standardize(tag));
|
||||
}
|
||||
|
||||
void setIcon(final String tag, final String icon)
|
||||
{
|
||||
configManager.setConfiguration(CONFIG_GROUP, ICON_SEARCH + Text.standardize(tag), icon);
|
||||
}
|
||||
|
||||
int size()
|
||||
{
|
||||
return tabs.size();
|
||||
|
||||
@@ -25,17 +25,12 @@
|
||||
*/
|
||||
package net.runelite.client.plugins.banktags.tabs;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.SpritePixels;
|
||||
import net.runelite.client.util.ImageUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.runelite.client.game.SpriteOverride;
|
||||
|
||||
@Slf4j
|
||||
public enum TabSprites
|
||||
@RequiredArgsConstructor
|
||||
public enum TabSprites implements SpriteOverride
|
||||
{
|
||||
INCINERATOR(-200, "incinerator.png"),
|
||||
TAB_BACKGROUND(-201, "tag-tab.png"),
|
||||
@@ -46,23 +41,7 @@ public enum TabSprites
|
||||
|
||||
@Getter
|
||||
private final int spriteId;
|
||||
private final BufferedImage image;
|
||||
|
||||
TabSprites(final int spriteId, final String imageName)
|
||||
{
|
||||
this.spriteId = spriteId;
|
||||
this.image = ImageUtil.getResourceStreamFromClass(this.getClass(), imageName);
|
||||
}
|
||||
|
||||
public static Map<Integer, SpritePixels> toMap(Client client)
|
||||
{
|
||||
final Map<Integer, SpritePixels> map = new HashMap<>();
|
||||
|
||||
for (TabSprites value : values())
|
||||
{
|
||||
map.put(value.spriteId, ImageUtil.getImageSpritePixels(value.image, client));
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
@Getter
|
||||
private final String fileName;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ import net.runelite.api.widgets.Widget;
|
||||
@EqualsAndHashCode(of = "tag")
|
||||
class TagTab
|
||||
{
|
||||
private final String tag;
|
||||
private String tag;
|
||||
private int iconItemId;
|
||||
private Widget background;
|
||||
private Widget icon;
|
||||
|
||||
@@ -26,15 +26,15 @@ package net.runelite.client.plugins.cannon;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.image.BufferedImage;
|
||||
import net.runelite.client.ui.overlay.infobox.Counter;
|
||||
import net.runelite.client.ui.overlay.infobox.InfoBox;
|
||||
|
||||
public class CannonCounter extends Counter
|
||||
public class CannonCounter extends InfoBox
|
||||
{
|
||||
private final CannonPlugin plugin;
|
||||
|
||||
public CannonCounter(BufferedImage img, CannonPlugin plugin)
|
||||
CannonCounter(BufferedImage img, CannonPlugin plugin)
|
||||
{
|
||||
super(img, plugin, String.valueOf(plugin.getCballsLeft()));
|
||||
super(img, plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
|
||||
@@ -75,7 +75,8 @@ public class CerberusPlugin extends Plugin
|
||||
@Subscribe
|
||||
public void onGameStateChanged(GameStateChanged event)
|
||||
{
|
||||
if (event.getGameState() == GameState.LOADING)
|
||||
GameState gameState = event.getGameState();
|
||||
if (gameState == GameState.LOGIN_SCREEN || gameState == GameState.HOPPING || gameState == GameState.CONNECTION_LOST)
|
||||
{
|
||||
ghosts.clear();
|
||||
}
|
||||
|
||||
@@ -299,7 +299,7 @@ public class ChatCommandsPlugin extends Plugin
|
||||
Widget boss = bossChildren[i];
|
||||
Widget kill = killsChildren[i];
|
||||
|
||||
String bossName = boss.getText();
|
||||
String bossName = boss.getText().replace(":", "");
|
||||
int kc = Integer.parseInt(kill.getText().replace(",", ""));
|
||||
if (kc != getKc(bossName))
|
||||
{
|
||||
@@ -1089,6 +1089,7 @@ public class ChatCommandsPlugin extends Plugin
|
||||
case "barrows":
|
||||
return "Barrows Chests";
|
||||
|
||||
// cox
|
||||
case "cox":
|
||||
case "xeric":
|
||||
case "chambers":
|
||||
@@ -1096,6 +1097,15 @@ public class ChatCommandsPlugin extends Plugin
|
||||
case "raids":
|
||||
return "Chambers of Xeric";
|
||||
|
||||
// cox cm
|
||||
case "cox cm":
|
||||
case "xeric cm":
|
||||
case "chambers cm":
|
||||
case "olm cm":
|
||||
case "raids cm":
|
||||
return "Chambers of Xeric Challenge Mode";
|
||||
|
||||
// tob
|
||||
case "tob":
|
||||
case "theatre":
|
||||
case "verzik":
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* Copyright (c) 2018, TheStonedTurtle <https://github.com/TheStonedTurtle>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -22,46 +22,34 @@
|
||||
* (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.ws;
|
||||
package net.runelite.client.plugins.chathistory;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import net.runelite.client.config.Config;
|
||||
import net.runelite.client.config.ConfigGroup;
|
||||
import net.runelite.client.config.ConfigItem;
|
||||
|
||||
public class SessionManager
|
||||
@ConfigGroup("chathistory")
|
||||
public interface ChatHistoryConfig extends Config
|
||||
{
|
||||
private static final ConcurrentMap<UUID, WSService> sessions = new ConcurrentHashMap<>();
|
||||
|
||||
public static void changeSessionUID(WSService service, UUID uuid)
|
||||
@ConfigItem(
|
||||
keyName = "retainChatHistory",
|
||||
name = "Retain Chat History",
|
||||
description = "Retains chat history when logging in/out or world hopping",
|
||||
position = 0
|
||||
)
|
||||
default boolean retainChatHistory()
|
||||
{
|
||||
synchronized (service)
|
||||
{
|
||||
remove(service);
|
||||
service.setUuid(uuid);
|
||||
sessions.put(uuid, service);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void remove(WSService service)
|
||||
@ConfigItem(
|
||||
keyName = "pmTargetCycling",
|
||||
name = "PM Target Cycling",
|
||||
description = "Pressing Tab while sending a PM will cycle the target username based on PM history",
|
||||
position = 1
|
||||
)
|
||||
default boolean pmTargetCycling()
|
||||
{
|
||||
synchronized (service)
|
||||
{
|
||||
UUID current = service.getUuid();
|
||||
if (current != null)
|
||||
{
|
||||
sessions.remove(current);
|
||||
service.setUuid(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static WSService findSession(UUID uuid)
|
||||
{
|
||||
return sessions.get(uuid);
|
||||
}
|
||||
|
||||
public static int getCount()
|
||||
{
|
||||
return sessions.size();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -25,47 +25,74 @@
|
||||
package net.runelite.client.plugins.chathistory;
|
||||
|
||||
import com.google.common.collect.EvictingQueue;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.inject.Provides;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.Iterator;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import javax.inject.Inject;
|
||||
import net.runelite.api.ChatMessageType;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.ScriptID;
|
||||
import net.runelite.api.VarClientInt;
|
||||
import net.runelite.api.VarClientStr;
|
||||
import net.runelite.api.events.ChatMessage;
|
||||
import net.runelite.api.events.MenuOptionClicked;
|
||||
import net.runelite.api.vars.InputType;
|
||||
import net.runelite.client.callback.ClientThread;
|
||||
import net.runelite.client.chat.ChatMessageManager;
|
||||
import net.runelite.client.chat.QueuedMessage;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
import net.runelite.client.input.KeyListener;
|
||||
import net.runelite.client.input.KeyManager;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.plugins.PluginDescriptor;
|
||||
import net.runelite.client.util.Text;
|
||||
|
||||
@PluginDescriptor(
|
||||
name = "Chat History",
|
||||
description = "Retain your chat history when logging in/out or world hopping"
|
||||
description = "Retain your chat history when logging in/out or world hopping",
|
||||
tags = {"chat", "history", "retain", "cycle", "pm"}
|
||||
)
|
||||
public class ChatHistoryPlugin extends Plugin
|
||||
public class ChatHistoryPlugin extends Plugin implements KeyListener
|
||||
{
|
||||
private static final String WELCOME_MESSAGE = "Welcome to Old School RuneScape.";
|
||||
private static final String CLEAR_HISTORY = "Clear history";
|
||||
private static final String CLEAR_PRIVATE = "<col=ffff00>Private:";
|
||||
private static final Set<ChatMessageType> ALLOWED_HISTORY = Sets.newHashSet(
|
||||
ChatMessageType.PUBLIC,
|
||||
ChatMessageType.PUBLIC_MOD,
|
||||
ChatMessageType.CLANCHAT,
|
||||
ChatMessageType.PRIVATE_MESSAGE_RECEIVED,
|
||||
ChatMessageType.PRIVATE_MESSAGE_SENT,
|
||||
ChatMessageType.PRIVATE_MESSAGE_RECEIVED_MOD,
|
||||
ChatMessageType.GAME
|
||||
);
|
||||
private static final int CYCLE_HOTKEY = KeyEvent.VK_TAB;
|
||||
|
||||
private Queue<QueuedMessage> messageQueue;
|
||||
private Deque<String> friends;
|
||||
|
||||
@Inject
|
||||
private Client client;
|
||||
|
||||
@Inject
|
||||
private ClientThread clientThread;
|
||||
|
||||
@Inject
|
||||
private ChatHistoryConfig config;
|
||||
|
||||
@Inject
|
||||
private KeyManager keyManager;
|
||||
|
||||
@Inject
|
||||
private ChatMessageManager chatMessageManager;
|
||||
|
||||
@Provides
|
||||
ChatHistoryConfig getConfig(ConfigManager configManager)
|
||||
{
|
||||
return configManager.getConfig(ChatHistoryConfig.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startUp()
|
||||
{
|
||||
messageQueue = EvictingQueue.create(100);
|
||||
friends = new ArrayDeque<>(5);
|
||||
keyManager.registerKeyListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -73,6 +100,9 @@ public class ChatHistoryPlugin extends Plugin
|
||||
{
|
||||
messageQueue.clear();
|
||||
messageQueue = null;
|
||||
friends.clear();
|
||||
friends = null;
|
||||
keyManager.unregisterKeyListener(this);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
@@ -82,6 +112,11 @@ public class ChatHistoryPlugin extends Plugin
|
||||
// of information that chat history was reset
|
||||
if (chatMessage.getMessage().equals(WELCOME_MESSAGE))
|
||||
{
|
||||
if (!config.retainChatHistory())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QueuedMessage queuedMessage;
|
||||
|
||||
while ((queuedMessage = messageQueue.poll()) != null)
|
||||
@@ -92,21 +127,33 @@ public class ChatHistoryPlugin extends Plugin
|
||||
return;
|
||||
}
|
||||
|
||||
if (ALLOWED_HISTORY.contains(chatMessage.getType()))
|
||||
switch (chatMessage.getType())
|
||||
{
|
||||
final QueuedMessage queuedMessage = QueuedMessage.builder()
|
||||
.type(chatMessage.getType())
|
||||
.name(chatMessage.getName())
|
||||
.sender(chatMessage.getSender())
|
||||
.value(nbsp(chatMessage.getMessage()))
|
||||
.runeLiteFormattedMessage(nbsp(chatMessage.getMessageNode().getRuneLiteFormatMessage()))
|
||||
.timestamp(chatMessage.getTimestamp())
|
||||
.build();
|
||||
case PRIVATE_MESSAGE_SENT:
|
||||
case PRIVATE_MESSAGE_RECEIVED:
|
||||
case PRIVATE_MESSAGE_RECEIVED_MOD:
|
||||
final String name = Text.removeTags(chatMessage.getName());
|
||||
// Remove to ensure uniqueness & its place in history
|
||||
friends.remove(name);
|
||||
friends.add(name);
|
||||
// intentional fall-through
|
||||
case PUBLIC:
|
||||
case PUBLIC_MOD:
|
||||
case CLANCHAT:
|
||||
case GAME:
|
||||
final QueuedMessage queuedMessage = QueuedMessage.builder()
|
||||
.type(chatMessage.getType())
|
||||
.name(chatMessage.getName())
|
||||
.sender(chatMessage.getSender())
|
||||
.value(nbsp(chatMessage.getMessage()))
|
||||
.runeLiteFormattedMessage(nbsp(chatMessage.getMessageNode().getRuneLiteFormatMessage()))
|
||||
.timestamp(chatMessage.getTimestamp())
|
||||
.build();
|
||||
|
||||
if (!messageQueue.contains(queuedMessage))
|
||||
{
|
||||
messageQueue.offer(queuedMessage);
|
||||
}
|
||||
if (!messageQueue.contains(queuedMessage))
|
||||
{
|
||||
messageQueue.offer(queuedMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,4 +190,64 @@ public class ChatHistoryPlugin extends Plugin
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e)
|
||||
{
|
||||
if (e.getKeyCode() != CYCLE_HOTKEY || !config.pmTargetCycling())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (client.getVar(VarClientInt.INPUT_TYPE) != InputType.PRIVATE_MESSAGE.getType())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
clientThread.invoke(() ->
|
||||
{
|
||||
final String target = findPreviousFriend();
|
||||
if (target == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final String currentMessage = client.getVar(VarClientStr.INPUT_TEXT);
|
||||
|
||||
client.runScript(ScriptID.OPEN_PRIVATE_MESSAGE_INTERFACE, target);
|
||||
|
||||
client.setVar(VarClientStr.INPUT_TEXT, currentMessage);
|
||||
client.runScript(ScriptID.CHAT_TEXT_INPUT_REBUILD, "");
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyTyped(KeyEvent e)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyReleased(KeyEvent e)
|
||||
{
|
||||
}
|
||||
|
||||
private String findPreviousFriend()
|
||||
{
|
||||
final String currentTarget = client.getVar(VarClientStr.PRIVATE_MESSAGE_TARGET);
|
||||
if (currentTarget == null || friends.isEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
for (Iterator<String> it = friends.descendingIterator(); it.hasNext(); )
|
||||
{
|
||||
String friend = it.next();
|
||||
if (friend.equals(currentTarget))
|
||||
{
|
||||
return it.hasNext() ? it.next() : friends.getLast();
|
||||
}
|
||||
}
|
||||
|
||||
return friends.getLast();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,8 +133,8 @@ public class EmoteClue extends ClueScroll implements TextClueScroll, LocationClu
|
||||
new EmoteClue("Panic by the pilot on White Wolf Mountain. Beware of double agents! Equip mithril platelegs, a ring of life and a rune axe.", GNOME_GLIDER_ON_WHITE_WOLF_MOUNTAIN, new WorldPoint(2847, 3499, 0), PANIC, item(MITHRIL_PLATELEGS), item(RING_OF_LIFE), item(RUNE_AXE)),
|
||||
new EmoteClue("Panic by the big egg where no one dare goes and the ground is burnt. Beware of double agents! Equip a dragon med helm, a TokTz-Ket-Xil, a brine sabre, rune platebody and an uncharged amulet of glory.", SOUTHEAST_CORNER_OF_LAVA_DRAGON_ISLE, new WorldPoint(3227, 3831, 0), PANIC, item(DRAGON_MED_HELM), item(TOKTZKETXIL), item(BRINE_SABRE), item(RUNE_PLATEBODY), item(AMULET_OF_GLORY)),
|
||||
new EmoteClue("Panic at the area flowers meet snow. Equip Blue D'hide vambs, a dragon spear and a rune plateskirt.", HALFWAY_DOWN_TROLLWEISS_MOUNTAIN, new WorldPoint(2776, 3781, 0), PANIC, item(BLUE_DHIDE_VAMB), item(DRAGON_SPEAR), item(RUNE_PLATESKIRT), item(SLED_4084)),
|
||||
new EmoteClue("Do a push up at the bank of the Warrior's guild. Beware of double agents! Equip a dragon battleaxe, a dragon defender and a slayer helm of any kind.", WARRIORS_GUILD_BANK_29047, new WorldPoint(2843, 3543, 0), PUSH_UP, item(DRAGON_BATTLEAXE), item(DRAGON_DEFENDER), any("Any slayer helmet", item(SLAYER_HELMET), item(BLACK_SLAYER_HELMET), item(GREEN_SLAYER_HELMET), item(PURPLE_SLAYER_HELMET), item(RED_SLAYER_HELMET), item(TURQUOISE_SLAYER_HELMET), item(SLAYER_HELMET_I), item(BLACK_SLAYER_HELMET_I), item(GREEN_SLAYER_HELMET_I), item(PURPLE_SLAYER_HELMET_I), item(RED_SLAYER_HELMET_I), item(TURQUOISE_SLAYER_HELMET_I))),
|
||||
new EmoteClue("Blow a raspberry at the bank of the Warrior's guild. Beware of double agents! Equip a dragon battleaxe, a dragon defender and a slayer helm of any kind.", WARRIORS_GUILD_BANK_29047, new WorldPoint(2843, 3543, 0), RASPBERRY, item(DRAGON_BATTLEAXE), item(DRAGON_DEFENDER), any("Any slayer helmet", item(SLAYER_HELMET), item(BLACK_SLAYER_HELMET), item(GREEN_SLAYER_HELMET), item(PURPLE_SLAYER_HELMET), item(RED_SLAYER_HELMET), item(TURQUOISE_SLAYER_HELMET), item(SLAYER_HELMET_I), item(BLACK_SLAYER_HELMET_I), item(GREEN_SLAYER_HELMET_I), item(PURPLE_SLAYER_HELMET_I), item(RED_SLAYER_HELMET_I), item(TURQUOISE_SLAYER_HELMET_I))),
|
||||
new EmoteClue("Do a push up at the bank of the Warrior's guild. Beware of double agents! Equip a dragon battleaxe, a dragon defender and a slayer helm of any kind.", WARRIORS_GUILD_BANK_29047, new WorldPoint(2843, 3543, 0), PUSH_UP, item(DRAGON_BATTLEAXE), item(DRAGON_DEFENDER), any("Any slayer helmet", item(SLAYER_HELMET), item(BLACK_SLAYER_HELMET), item(GREEN_SLAYER_HELMET), item(PURPLE_SLAYER_HELMET), item(RED_SLAYER_HELMET), item(TURQUOISE_SLAYER_HELMET), item(SLAYER_HELMET_I), item(BLACK_SLAYER_HELMET_I), item(GREEN_SLAYER_HELMET_I), item(PURPLE_SLAYER_HELMET_I), item(RED_SLAYER_HELMET_I), item(TURQUOISE_SLAYER_HELMET_I), item(HYDRA_SLAYER_HELMET), item(HYDRA_SLAYER_HELMET_I))),
|
||||
new EmoteClue("Blow a raspberry at the bank of the Warrior's guild. Beware of double agents! Equip a dragon battleaxe, a dragon defender and a slayer helm of any kind.", WARRIORS_GUILD_BANK_29047, new WorldPoint(2843, 3543, 0), RASPBERRY, item(DRAGON_BATTLEAXE), item(DRAGON_DEFENDER), any("Any slayer helmet", item(SLAYER_HELMET), item(BLACK_SLAYER_HELMET), item(GREEN_SLAYER_HELMET), item(PURPLE_SLAYER_HELMET), item(RED_SLAYER_HELMET), item(TURQUOISE_SLAYER_HELMET), item(SLAYER_HELMET_I), item(BLACK_SLAYER_HELMET_I), item(GREEN_SLAYER_HELMET_I), item(PURPLE_SLAYER_HELMET_I), item(RED_SLAYER_HELMET_I), item(TURQUOISE_SLAYER_HELMET_I), item(HYDRA_SLAYER_HELMET), item(HYDRA_SLAYER_HELMET_I))),
|
||||
new EmoteClue("Blow a raspberry at the monkey cage in Ardougne Zoo. Equip a studded leather body, bronze platelegs and a normal staff with no orb.", NEAR_THE_PARROTS_IN_ARDOUGNE_ZOO, new WorldPoint(2607, 3282, 0), RASPBERRY, item(STUDDED_BODY), item(BRONZE_PLATELEGS), item(STAFF)),
|
||||
new EmoteClue("Blow raspberries outside the entrance to Keep Le Faye. Equip a coif, an iron platebody and leather gloves.", OUTSIDE_KEEP_LE_FAYE, new WorldPoint(2757, 3401, 0), RASPBERRY, item(COIF), item(IRON_PLATEBODY), item(LEATHER_GLOVES)),
|
||||
new EmoteClue("Blow a raspberry in the Fishing Guild bank. Beware of double agents! Equip an elemental shield, blue dragonhide chaps and a rune warhammer.", FISHING_GUILD_BANK, new WorldPoint(2588, 3419, 0), RASPBERRY, item(ELEMENTAL_SHIELD), item(BLUE_DHIDE_CHAPS), item(RUNE_WARHAMMER)),
|
||||
|
||||
@@ -78,7 +78,6 @@ class CookingOverlay extends Overlay
|
||||
return null;
|
||||
}
|
||||
|
||||
panelComponent.setPreferredSize(new Dimension(145, 0));
|
||||
panelComponent.getChildren().clear();
|
||||
|
||||
if (isCooking() || Duration.between(session.getLastCookingAction(), Instant.now()).getSeconds() < COOK_TIMEOUT)
|
||||
|
||||
@@ -347,6 +347,12 @@ class DevToolsOverlay extends Overlay
|
||||
{
|
||||
graphics.drawPolygon(p);
|
||||
}
|
||||
|
||||
p = decorObject.getConvexHull2();
|
||||
if (p != null)
|
||||
{
|
||||
graphics.drawPolygon(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -183,6 +183,9 @@ public class WidgetInfoTableModel extends AbstractTableModel
|
||||
out.add(new WidgetField<>("ScrollHeight", Widget::getScrollHeight, Widget::setScrollHeight, Integer.class));
|
||||
out.add(new WidgetField<>("DragDeadZone", Widget::getDragDeadZone, Widget::setDragDeadZone, Integer.class));
|
||||
out.add(new WidgetField<>("DragDeadTime", Widget::getDragDeadTime, Widget::setDragDeadTime, Integer.class));
|
||||
out.add(new WidgetField<>("NoClickThrough", Widget::getNoClickThrough, Widget::setNoClickThrough, Boolean.class));
|
||||
out.add(new WidgetField<>("NoScrollThrough", Widget::getNoScrollThrough, Widget::setNoScrollThrough, Boolean.class));
|
||||
out.add(new WidgetField<>("TargetVerb", Widget::getTargetVerb, Widget::setTargetVerb, String.class));
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -130,6 +130,7 @@ public class DiscordPlugin extends Plugin
|
||||
|
||||
clientToolbar.addNavigation(discordButton);
|
||||
checkForGameStateUpdate();
|
||||
checkForAreaUpdate();
|
||||
|
||||
if (discordService.getCurrentUser() != null)
|
||||
{
|
||||
|
||||
@@ -34,6 +34,7 @@ import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import javax.inject.Inject;
|
||||
import lombok.Data;
|
||||
import net.runelite.client.RuneLiteProperties;
|
||||
import net.runelite.client.discord.DiscordPresence;
|
||||
import net.runelite.client.discord.DiscordService;
|
||||
import net.runelite.client.ws.PartyService;
|
||||
@@ -57,14 +58,16 @@ class DiscordState
|
||||
private final DiscordService discordService;
|
||||
private final DiscordConfig config;
|
||||
private PartyService party;
|
||||
private final RuneLiteProperties properties;
|
||||
private DiscordPresence lastPresence;
|
||||
|
||||
@Inject
|
||||
private DiscordState(final DiscordService discordService, final DiscordConfig config, final PartyService party)
|
||||
private DiscordState(final DiscordService discordService, final DiscordConfig config, final PartyService party, final RuneLiteProperties properties)
|
||||
{
|
||||
this.discordService = discordService;
|
||||
this.config = config;
|
||||
this.party = party;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,6 +93,7 @@ class DiscordState
|
||||
final DiscordPresence.DiscordPresenceBuilder presenceBuilder = DiscordPresence.builder()
|
||||
.state(lastPresence.getState())
|
||||
.details(lastPresence.getDetails())
|
||||
.largeImageText(lastPresence.getLargeImageText())
|
||||
.startTimestamp(lastPresence.getStartTimestamp())
|
||||
.smallImageKey(lastPresence.getSmallImageKey())
|
||||
.partyMax(lastPresence.getPartyMax())
|
||||
@@ -168,11 +172,15 @@ class DiscordState
|
||||
}
|
||||
}
|
||||
|
||||
// Replace snapshot with + to make tooltip shorter (so it will span only 1 line)
|
||||
final String versionShortHand = properties.getVersion().replace("-SNAPSHOT", "+");
|
||||
|
||||
final DiscordPresence.DiscordPresenceBuilder presenceBuilder = DiscordPresence.builder()
|
||||
.state(MoreObjects.firstNonNull(state, ""))
|
||||
.details(MoreObjects.firstNonNull(details, ""))
|
||||
.largeImageText(properties.getTitle() + " v" + versionShortHand)
|
||||
.startTimestamp(event.getStart())
|
||||
.smallImageKey(MoreObjects.firstNonNull(imageKey, "default"))
|
||||
.smallImageKey(imageKey)
|
||||
.partyMax(PARTY_MAX)
|
||||
.partySize(party.getMembers().size());
|
||||
|
||||
|
||||
@@ -24,10 +24,12 @@
|
||||
*/
|
||||
package net.runelite.client.plugins.discord;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Value;
|
||||
import net.runelite.http.api.ws.messages.party.PartyMemberMessage;
|
||||
|
||||
@Value
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
class DiscordUserInfo extends PartyMemberMessage
|
||||
{
|
||||
private final String userId;
|
||||
|
||||
@@ -147,7 +147,8 @@ public class FishingPlugin extends Plugin
|
||||
@Subscribe
|
||||
public void onGameStateChanged(GameStateChanged gameStateChanged)
|
||||
{
|
||||
if (gameStateChanged.getGameState() == GameState.LOADING)
|
||||
GameState gameState = gameStateChanged.getGameState();
|
||||
if (gameState == GameState.CONNECTION_LOST || gameState == GameState.LOGIN_SCREEN || gameState == GameState.HOPPING)
|
||||
{
|
||||
fishingSpots.clear();
|
||||
minnowSpots.clear();
|
||||
|
||||
@@ -1151,8 +1151,6 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
||||
gl.glTexSubImage2D(gl.GL_TEXTURE_2D, 0, 0, 0, width, height, gl.GL_BGRA, gl.GL_UNSIGNED_INT_8_8_8_8_REV, interfaceBuffer);
|
||||
}
|
||||
|
||||
gl.glBindTexture(gl.GL_TEXTURE_2D, interfaceTexture);
|
||||
|
||||
if (client.isStretchedEnabled())
|
||||
{
|
||||
Dimension dim = client.getStretchedDimensions();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2019, Adam <Adam@sigterm.info>
|
||||
* Copyright (c) 2017, Robbie <https://github.com/rbbi>
|
||||
* Copyright (c) 2018, SomeoneWithAnInternetConnection
|
||||
* All rights reserved.
|
||||
@@ -46,6 +46,7 @@ import net.runelite.api.ChatMessageType;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.api.GrandExchangeOffer;
|
||||
import net.runelite.api.GrandExchangeOfferState;
|
||||
import net.runelite.api.ItemComposition;
|
||||
import net.runelite.api.MenuAction;
|
||||
import net.runelite.api.MenuEntry;
|
||||
@@ -56,11 +57,15 @@ import net.runelite.api.events.GameStateChanged;
|
||||
import net.runelite.api.events.GameTick;
|
||||
import net.runelite.api.events.GrandExchangeOfferChanged;
|
||||
import net.runelite.api.events.MenuEntryAdded;
|
||||
import net.runelite.api.events.SessionClose;
|
||||
import net.runelite.api.events.SessionOpen;
|
||||
import net.runelite.api.events.WidgetLoaded;
|
||||
import net.runelite.api.widgets.Widget;
|
||||
import net.runelite.api.widgets.WidgetID;
|
||||
import net.runelite.api.widgets.WidgetInfo;
|
||||
import net.runelite.client.Notifier;
|
||||
import net.runelite.client.account.AccountSession;
|
||||
import net.runelite.client.account.SessionManager;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
@@ -73,8 +78,10 @@ import net.runelite.client.ui.NavigationButton;
|
||||
import net.runelite.client.util.ImageUtil;
|
||||
import net.runelite.client.util.StackFormatter;
|
||||
import net.runelite.client.util.Text;
|
||||
import net.runelite.http.api.osbuddy.GrandExchangeClient;
|
||||
import net.runelite.http.api.osbuddy.GrandExchangeResult;
|
||||
import net.runelite.http.api.ge.GrandExchangeClient;
|
||||
import net.runelite.http.api.ge.GrandExchangeTrade;
|
||||
import net.runelite.http.api.osbuddy.OSBGrandExchangeClient;
|
||||
import net.runelite.http.api.osbuddy.OSBGrandExchangeResult;
|
||||
|
||||
@PluginDescriptor(
|
||||
name = "Grand Exchange",
|
||||
@@ -86,7 +93,7 @@ public class GrandExchangePlugin extends Plugin
|
||||
{
|
||||
private static final int OFFER_CONTAINER_ITEM = 21;
|
||||
private static final int OFFER_DEFAULT_ITEM_ID = 6512;
|
||||
private static final GrandExchangeClient CLIENT = new GrandExchangeClient();
|
||||
private static final OSBGrandExchangeClient CLIENT = new OSBGrandExchangeClient();
|
||||
private static final String OSB_GE_TEXT = "<br>OSBuddy Actively traded price: ";
|
||||
|
||||
private static final String BUY_LIMIT_GE_TEXT = "<br>Buy limit: ";
|
||||
@@ -134,10 +141,38 @@ public class GrandExchangePlugin extends Plugin
|
||||
@Inject
|
||||
private ScheduledExecutorService executorService;
|
||||
|
||||
@Inject
|
||||
private SessionManager sessionManager;
|
||||
|
||||
@Inject
|
||||
private ConfigManager configManager;
|
||||
|
||||
private Widget grandExchangeText;
|
||||
private Widget grandExchangeItem;
|
||||
private Map<Integer, Integer> itemGELimits;
|
||||
|
||||
private GrandExchangeClient grandExchangeClient;
|
||||
|
||||
private SavedOffer getOffer(int slot)
|
||||
{
|
||||
String offer = configManager.getConfiguration("geoffer." + client.getUsername().toLowerCase(), Integer.toString(slot));
|
||||
if (offer == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return GSON.fromJson(offer, SavedOffer.class);
|
||||
}
|
||||
|
||||
private void setOffer(int slot, SavedOffer offer)
|
||||
{
|
||||
configManager.setConfiguration("geoffer." + client.getUsername().toLowerCase(), Integer.toString(slot), GSON.toJson(offer));
|
||||
}
|
||||
|
||||
private void deleteOffer(int slot)
|
||||
{
|
||||
configManager.unsetConfiguration("geoffer." + client.getUsername().toLowerCase(), Integer.toString(slot));
|
||||
}
|
||||
|
||||
@Provides
|
||||
GrandExchangeConfig provideConfig(ConfigManager configManager)
|
||||
{
|
||||
@@ -167,6 +202,12 @@ public class GrandExchangePlugin extends Plugin
|
||||
mouseManager.registerMouseListener(inputListener);
|
||||
keyManager.registerKeyListener(inputListener);
|
||||
}
|
||||
|
||||
AccountSession accountSession = sessionManager.getAccountSession();
|
||||
if (accountSession != null)
|
||||
{
|
||||
grandExchangeClient = new GrandExchangeClient(accountSession.getUuid());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -178,6 +219,27 @@ public class GrandExchangePlugin extends Plugin
|
||||
grandExchangeText = null;
|
||||
grandExchangeItem = null;
|
||||
itemGELimits = null;
|
||||
grandExchangeClient = null;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onSessionOpen(SessionOpen sessionOpen)
|
||||
{
|
||||
AccountSession accountSession = sessionManager.getAccountSession();
|
||||
if (accountSession.getUuid() != null)
|
||||
{
|
||||
grandExchangeClient = new GrandExchangeClient(accountSession.getUuid());
|
||||
}
|
||||
else
|
||||
{
|
||||
grandExchangeClient = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onSessionClose(SessionClose sessionClose)
|
||||
{
|
||||
grandExchangeClient = null;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
@@ -204,11 +266,79 @@ public class GrandExchangePlugin extends Plugin
|
||||
@Subscribe
|
||||
public void onGrandExchangeOfferChanged(GrandExchangeOfferChanged offerEvent)
|
||||
{
|
||||
GrandExchangeOffer offer = offerEvent.getOffer();
|
||||
final int slot = offerEvent.getSlot();
|
||||
final GrandExchangeOffer offer = offerEvent.getOffer();
|
||||
|
||||
ItemComposition offerItem = itemManager.getItemComposition(offer.getItemId());
|
||||
boolean shouldStack = offerItem.isStackable() || offer.getTotalQuantity() > 1;
|
||||
BufferedImage itemImage = itemManager.getImage(offer.getItemId(), offer.getTotalQuantity(), shouldStack);
|
||||
SwingUtilities.invokeLater(() -> panel.getOffersPanel().updateOffer(offerItem, itemImage, offerEvent.getOffer(), offerEvent.getSlot()));
|
||||
SwingUtilities.invokeLater(() -> panel.getOffersPanel().updateOffer(offerItem, itemImage, offer, slot));
|
||||
|
||||
submitTrades(slot, offer);
|
||||
|
||||
updateConfig(slot, offer);
|
||||
}
|
||||
|
||||
private void submitTrades(int slot, GrandExchangeOffer offer)
|
||||
{
|
||||
if (grandExchangeClient == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Only interested in offers which are fully bought/sold
|
||||
if (offer.getState() != GrandExchangeOfferState.BOUGHT && offer.getState() != GrandExchangeOfferState.SOLD)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SavedOffer savedOffer = getOffer(slot);
|
||||
if (!shouldUpdate(savedOffer, offer))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// getPrice() is the price of the offer, not necessarily what the item bought at
|
||||
int priceEach = offer.getSpent() / offer.getTotalQuantity();
|
||||
|
||||
GrandExchangeTrade grandExchangeTrade = new GrandExchangeTrade();
|
||||
grandExchangeTrade.setBuy(offer.getState() == GrandExchangeOfferState.BOUGHT);
|
||||
grandExchangeTrade.setItemId(offer.getItemId());
|
||||
grandExchangeTrade.setQuantity(offer.getTotalQuantity());
|
||||
grandExchangeTrade.setPrice(priceEach);
|
||||
|
||||
log.debug("Submitting trade: {}", grandExchangeTrade);
|
||||
grandExchangeClient.submit(grandExchangeTrade);
|
||||
}
|
||||
|
||||
private void updateConfig(int slot, GrandExchangeOffer offer)
|
||||
{
|
||||
if (offer.getState() == GrandExchangeOfferState.EMPTY)
|
||||
{
|
||||
deleteOffer(slot);
|
||||
}
|
||||
else
|
||||
{
|
||||
SavedOffer savedOffer = new SavedOffer();
|
||||
savedOffer.setItemId(offer.getItemId());
|
||||
savedOffer.setQuantitySold(offer.getQuantitySold());
|
||||
savedOffer.setTotalQuantity(offer.getTotalQuantity());
|
||||
savedOffer.setPrice(offer.getPrice());
|
||||
savedOffer.setSpent(offer.getSpent());
|
||||
savedOffer.setState(offer.getState());
|
||||
setOffer(slot, savedOffer);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldUpdate(SavedOffer savedOffer, GrandExchangeOffer grandExchangeOffer)
|
||||
{
|
||||
if (savedOffer == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only update offer if state has changed
|
||||
return savedOffer.getState() != grandExchangeOffer.getState();
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
@@ -346,7 +476,7 @@ public class GrandExchangePlugin extends Plugin
|
||||
|
||||
try
|
||||
{
|
||||
final GrandExchangeResult result = CLIENT.lookupItem(itemId);
|
||||
final OSBGrandExchangeResult result = CLIENT.lookupItem(itemId);
|
||||
final String text = geText.getText() + OSB_GE_TEXT + StackFormatter.formatNumber(result.getOverall_average());
|
||||
geText.setText(text);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user