update to latest and fix style
This commit is contained in:
@@ -29,7 +29,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>net.runelite</groupId>
|
<groupId>net.runelite</groupId>
|
||||||
<artifactId>runelite-parent</artifactId>
|
<artifactId>runelite-parent</artifactId>
|
||||||
<version>1.5.12-SNAPSHOT</version>
|
<version>1.5.14-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>cache-client</artifactId>
|
<artifactId>cache-client</artifactId>
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>net.runelite</groupId>
|
<groupId>net.runelite</groupId>
|
||||||
<artifactId>runelite-parent</artifactId>
|
<artifactId>runelite-parent</artifactId>
|
||||||
<version>1.5.12-SNAPSHOT</version>
|
<version>1.5.14-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<name>Cache Updater</name>
|
<name>Cache Updater</name>
|
||||||
|
|||||||
2
cache/pom.xml
vendored
2
cache/pom.xml
vendored
@@ -29,7 +29,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>net.runelite</groupId>
|
<groupId>net.runelite</groupId>
|
||||||
<artifactId>runelite-parent</artifactId>
|
<artifactId>runelite-parent</artifactId>
|
||||||
<version>1.5.12-SNAPSHOT</version>
|
<version>1.5.14-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>cache</artifactId>
|
<artifactId>cache</artifactId>
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>net.runelite</groupId>
|
<groupId>net.runelite</groupId>
|
||||||
<artifactId>runelite-parent</artifactId>
|
<artifactId>runelite-parent</artifactId>
|
||||||
<version>1.5.12-SNAPSHOT</version>
|
<version>1.5.14-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<name>Web API</name>
|
<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;
|
package net.runelite.http.api.loottracker;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@@ -37,4 +38,5 @@ public class LootRecord
|
|||||||
private String eventId;
|
private String eventId;
|
||||||
private LootRecordType type;
|
private LootRecordType type;
|
||||||
private Collection<GameItem> drops;
|
private Collection<GameItem> drops;
|
||||||
|
private Instant time;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,9 +35,9 @@ import okhttp3.Request;
|
|||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
|
|
||||||
@Slf4j
|
@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()
|
final HttpUrl url = RuneLiteAPI.getApiBase().newBuilder()
|
||||||
.addPathSegment("osb")
|
.addPathSegment("osb")
|
||||||
@@ -59,7 +59,7 @@ public class GrandExchangeClient
|
|||||||
}
|
}
|
||||||
|
|
||||||
final InputStream in = response.body().byteStream();
|
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)
|
catch (JsonParseException ex)
|
||||||
{
|
{
|
||||||
@@ -28,7 +28,7 @@ import java.time.Instant;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class GrandExchangeResult
|
public class OSBGrandExchangeResult
|
||||||
{
|
{
|
||||||
private int item_id;
|
private int item_id;
|
||||||
private int buy_average;
|
private int buy_average;
|
||||||
@@ -25,10 +25,12 @@
|
|||||||
package net.runelite.http.api.ws.messages.party;
|
package net.runelite.http.api.ws.messages.party;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
import net.runelite.http.api.ws.WebsocketMessage;
|
import net.runelite.http.api.ws.WebsocketMessage;
|
||||||
|
|
||||||
@Value
|
@Value
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class Join extends WebsocketMessage
|
public class Join extends WebsocketMessage
|
||||||
{
|
{
|
||||||
private final UUID partyId;
|
private final UUID partyId;
|
||||||
|
|||||||
@@ -25,10 +25,12 @@
|
|||||||
package net.runelite.http.api.ws.messages.party;
|
package net.runelite.http.api.ws.messages.party;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
import net.runelite.http.api.ws.WebsocketMessage;
|
import net.runelite.http.api.ws.WebsocketMessage;
|
||||||
|
|
||||||
@Value
|
@Value
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class UserJoin extends WebsocketMessage
|
public class UserJoin extends WebsocketMessage
|
||||||
{
|
{
|
||||||
private final UUID memberId;
|
private final UUID memberId;
|
||||||
|
|||||||
@@ -25,10 +25,12 @@
|
|||||||
package net.runelite.http.api.ws.messages.party;
|
package net.runelite.http.api.ws.messages.party;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
import net.runelite.http.api.ws.WebsocketMessage;
|
import net.runelite.http.api.ws.WebsocketMessage;
|
||||||
|
|
||||||
@Value
|
@Value
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class UserPart extends WebsocketMessage
|
public class UserPart extends WebsocketMessage
|
||||||
{
|
{
|
||||||
private final UUID memberId;
|
private final UUID memberId;
|
||||||
|
|||||||
@@ -24,9 +24,11 @@
|
|||||||
*/
|
*/
|
||||||
package net.runelite.http.api.ws.messages.party;
|
package net.runelite.http.api.ws.messages.party;
|
||||||
|
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
|
|
||||||
@Value
|
@Value
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class UserSync extends PartyMemberMessage
|
public class UserSync extends PartyMemberMessage
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>net.runelite</groupId>
|
<groupId>net.runelite</groupId>
|
||||||
<artifactId>runelite-parent</artifactId>
|
<artifactId>runelite-parent</artifactId>
|
||||||
<version>1.5.12-SNAPSHOT</version>
|
<version>1.5.14-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<name>Web Service</name>
|
<name>Web Service</name>
|
||||||
@@ -55,6 +55,10 @@
|
|||||||
<artifactId>spring-boot-devtools</artifactId>
|
<artifactId>spring-boot-devtools</artifactId>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-jdbc</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mapstruct</groupId>
|
<groupId>org.mapstruct</groupId>
|
||||||
@@ -130,6 +134,11 @@
|
|||||||
<version>3.7.0</version>
|
<version>3.7.0</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.h2database</groupId>
|
||||||
|
<artifactId>h2</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
|
|||||||
@@ -25,13 +25,11 @@
|
|||||||
package net.runelite.http.service;
|
package net.runelite.http.service;
|
||||||
|
|
||||||
import ch.qos.logback.classic.LoggerContext;
|
import ch.qos.logback.classic.LoggerContext;
|
||||||
|
import com.google.common.base.Strings;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.naming.Context;
|
|
||||||
import javax.naming.InitialContext;
|
|
||||||
import javax.naming.NamingException;
|
|
||||||
import javax.servlet.ServletContext;
|
import javax.servlet.ServletContext;
|
||||||
import javax.servlet.ServletContextEvent;
|
import javax.servlet.ServletContextEvent;
|
||||||
import javax.servlet.ServletContextListener;
|
import javax.servlet.ServletContextListener;
|
||||||
@@ -44,11 +42,17 @@ import okhttp3.Cache;
|
|||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
import org.slf4j.ILoggerFactory;
|
import org.slf4j.ILoggerFactory;
|
||||||
import org.slf4j.impl.StaticLoggerBinder;
|
import org.slf4j.impl.StaticLoggerBinder;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
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.builder.SpringApplicationBuilder;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
import org.springframework.boot.web.support.SpringBootServletInitializer;
|
import org.springframework.boot.web.support.SpringBootServletInitializer;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;
|
||||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
import org.sql2o.Sql2o;
|
import org.sql2o.Sql2o;
|
||||||
import org.sql2o.converters.Converter;
|
import org.sql2o.converters.Converter;
|
||||||
@@ -56,6 +60,7 @@ import org.sql2o.quirks.NoQuirks;
|
|||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
@EnableScheduling
|
@EnableScheduling
|
||||||
|
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class SpringBootWebApplication extends SpringBootServletInitializer
|
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 new DataSourceProperties();
|
||||||
return (Context) initCtx.lookup("java:comp/env");
|
}
|
||||||
|
|
||||||
|
@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")
|
@Bean("Runelite SQL2O")
|
||||||
Sql2o sql2o() throws NamingException
|
public Sql2o sql2o(@Qualifier("runelite") DataSource dataSource)
|
||||||
{
|
{
|
||||||
DataSource dataSource = (DataSource) getContext().lookup("jdbc/runelite");
|
return createSql2oFromDataSource(dataSource);
|
||||||
Map<Class, Converter> converters = new HashMap<>();
|
|
||||||
converters.put(Instant.class, new InstantConverter());
|
|
||||||
return new Sql2o(dataSource, new NoQuirks(converters));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean("Runelite Cache SQL2O")
|
@Bean("Runelite Cache SQL2O")
|
||||||
Sql2o cacheSql2o() throws NamingException
|
public Sql2o cacheSql2o(@Qualifier("runelite-cache") DataSource dataSource)
|
||||||
{
|
{
|
||||||
DataSource dataSource = (DataSource) getContext().lookup("jdbc/runelite-cache2");
|
return createSql2oFromDataSource(dataSource);
|
||||||
Map<Class, Converter> converters = new HashMap<>();
|
|
||||||
converters.put(Instant.class, new InstantConverter());
|
|
||||||
return new Sql2o(dataSource, new NoQuirks(converters));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean("Runelite XP Tracker SQL2O")
|
@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");
|
return createSql2oFromDataSource(dataSource);
|
||||||
Map<Class, Converter> converters = new HashMap<>();
|
}
|
||||||
|
|
||||||
|
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());
|
converters.put(Instant.class, new InstantConverter());
|
||||||
return new Sql2o(dataSource, new NoQuirks(converters));
|
return new Sql2o(dataSource, new NoQuirks(converters));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,22 +24,42 @@
|
|||||||
*/
|
*/
|
||||||
package net.runelite.http.service;
|
package net.runelite.http.service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import net.runelite.http.api.RuneLiteAPI;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.http.MediaType;
|
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.ContentNegotiationConfigurer;
|
||||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure .js as application/json to trick Cloudflare into caching json responses
|
|
||||||
*/
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebMvc
|
@EnableWebMvc
|
||||||
public class SpringContentNegotiationConfigurer extends WebMvcConfigurerAdapter
|
public class SpringWebMvcConfigurer extends WebMvcConfigurerAdapter
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Configure .js as application/json to trick Cloudflare into caching json responses
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void configureContentNegotiation(ContentNegotiationConfigurer configurer)
|
public void configureContentNegotiation(ContentNegotiationConfigurer configurer)
|
||||||
{
|
{
|
||||||
configurer.mediaType("js", MediaType.APPLICATION_JSON);
|
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.SessionEntry;
|
||||||
import net.runelite.http.service.account.beans.UserEntry;
|
import net.runelite.http.service.account.beans.UserEntry;
|
||||||
import net.runelite.http.service.util.redis.RedisPool;
|
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.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -241,12 +239,6 @@ public class AccountService
|
|||||||
LoginResponse response = new LoginResponse();
|
LoginResponse response = new LoginResponse();
|
||||||
response.setUsername(username);
|
response.setUsername(username);
|
||||||
|
|
||||||
WSService service = SessionManager.findSession(uuid);
|
|
||||||
if (service != null)
|
|
||||||
{
|
|
||||||
service.send(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
try (Jedis jedis = jedisPool.getResource())
|
try (Jedis jedis = jedisPool.getResource())
|
||||||
{
|
{
|
||||||
jedis.publish("session." + uuid, websocketGson.toJson(response, WebsocketMessage.class));
|
jedis.publish("session." + uuid, websocketGson.toJson(response, WebsocketMessage.class));
|
||||||
@@ -276,10 +268,4 @@ public class AccountService
|
|||||||
{
|
{
|
||||||
auth.handle(request, response);
|
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.InvalidKeyException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.runelite.cache.ConfigType;
|
import net.runelite.cache.ConfigType;
|
||||||
@@ -233,6 +234,11 @@ public class CacheService
|
|||||||
public List<ItemDefinition> getItems() throws IOException
|
public List<ItemDefinition> getItems() throws IOException
|
||||||
{
|
{
|
||||||
CacheEntry cache = findMostRecent();
|
CacheEntry cache = findMostRecent();
|
||||||
|
if (cache == null)
|
||||||
|
{
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
IndexEntry indexEntry = findIndexForCache(cache, IndexType.CONFIGS.getNumber());
|
IndexEntry indexEntry = findIndexForCache(cache, IndexType.CONFIGS.getNumber());
|
||||||
ArchiveEntry archiveEntry = findArchiveForIndex(indexEntry, ConfigType.ITEM.getId());
|
ArchiveEntry archiveEntry = findArchiveForIndex(indexEntry, ConfigType.ITEM.getId());
|
||||||
ArchiveFiles archiveFiles = getArchiveFiles(archiveEntry);
|
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;
|
package net.runelite.http.service.config;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.annotation.Nullable;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import net.runelite.http.api.config.ConfigEntry;
|
import net.runelite.http.api.config.ConfigEntry;
|
||||||
import net.runelite.http.api.config.Configuration;
|
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.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.stereotype.Service;
|
||||||
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.sql2o.Connection;
|
import org.sql2o.Connection;
|
||||||
import org.sql2o.Sql2o;
|
import org.sql2o.Sql2o;
|
||||||
import org.sql2o.Sql2oException;
|
import org.sql2o.Sql2oException;
|
||||||
|
|
||||||
@RestController
|
@Service
|
||||||
@RequestMapping("/config")
|
|
||||||
public class ConfigService
|
public class ConfigService
|
||||||
{
|
{
|
||||||
private static final String CREATE_CONFIG = "CREATE TABLE IF NOT EXISTS `config` (\n"
|
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;";
|
+ " ADD CONSTRAINT `user_fk` FOREIGN KEY (`user`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;";
|
||||||
|
|
||||||
private final Sql2o sql2o;
|
private final Sql2o sql2o;
|
||||||
private final AuthFilter auth;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ConfigService(
|
public ConfigService(
|
||||||
@Qualifier("Runelite SQL2O") Sql2o sql2o,
|
@Qualifier("Runelite SQL2O") Sql2o sql2o
|
||||||
AuthFilter auth
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this.sql2o = sql2o;
|
this.sql2o = sql2o;
|
||||||
this.auth = auth;
|
|
||||||
|
|
||||||
try (Connection con = sql2o.open())
|
try (Connection con = sql2o.open())
|
||||||
{
|
{
|
||||||
@@ -87,71 +74,45 @@ public class ConfigService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping
|
public Configuration get(int userId)
|
||||||
public Configuration get(HttpServletRequest request, HttpServletResponse response) throws IOException
|
|
||||||
{
|
{
|
||||||
SessionEntry session = auth.handle(request, response);
|
|
||||||
|
|
||||||
if (session == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<ConfigEntry> config;
|
List<ConfigEntry> config;
|
||||||
|
|
||||||
try (Connection con = sql2o.open())
|
try (Connection con = sql2o.open())
|
||||||
{
|
{
|
||||||
config = con.createQuery("select `key`, value from config where user = :user")
|
config = con.createQuery("select `key`, value from config where user = :user")
|
||||||
.addParameter("user", session.getUser())
|
.addParameter("user", userId)
|
||||||
.executeAndFetch(ConfigEntry.class);
|
.executeAndFetch(ConfigEntry.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Configuration(config);
|
return new Configuration(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(path = "/{key:.+}", method = PUT)
|
|
||||||
public void setKey(
|
public void setKey(
|
||||||
HttpServletRequest request,
|
int userId,
|
||||||
HttpServletResponse response,
|
String key,
|
||||||
@PathVariable String key,
|
@Nullable String value
|
||||||
@RequestBody(required = false) String value
|
)
|
||||||
) throws IOException
|
|
||||||
{
|
{
|
||||||
SessionEntry session = auth.handle(request, response);
|
|
||||||
|
|
||||||
if (session == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try (Connection con = sql2o.open())
|
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")
|
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("key", key)
|
||||||
.addParameter("value", value != null ? value : "")
|
.addParameter("value", value != null ? value : "")
|
||||||
.executeUpdate();
|
.executeUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(path = "/{key:.+}", method = DELETE)
|
|
||||||
public void unsetKey(
|
public void unsetKey(
|
||||||
HttpServletRequest request,
|
int userId,
|
||||||
HttpServletResponse response,
|
String key
|
||||||
@PathVariable String key
|
)
|
||||||
) throws IOException
|
|
||||||
{
|
{
|
||||||
SessionEntry session = auth.handle(request, response);
|
|
||||||
|
|
||||||
if (session == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try (Connection con = sql2o.open())
|
try (Connection con = sql2o.open())
|
||||||
{
|
{
|
||||||
con.createQuery("delete from config where user = :user and `key` = :key")
|
con.createQuery("delete from config where user = :user and `key` = :key")
|
||||||
.addParameter("user", session.getUser())
|
.addParameter("user", userId)
|
||||||
.addParameter("key", key)
|
.addParameter("key", key)
|
||||||
.executeUpdate();
|
.executeUpdate();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ public class FeedController
|
|||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
log.warn(null, e);
|
log.warn(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -80,7 +80,7 @@ public class FeedController
|
|||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
log.warn(null, e);
|
log.warn(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -89,7 +89,7 @@ public class FeedController
|
|||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
log.warn(null, e);
|
log.warn(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
feedResult = new FeedResult(items);
|
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
|
public void reloadItems() throws IOException
|
||||||
{
|
{
|
||||||
List<ItemDefinition> items = cacheService.getItems();
|
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()
|
tradeableItems = items.stream()
|
||||||
.filter(item -> item.isTradeable)
|
.filter(item -> item.isTradeable)
|
||||||
.mapToInt(item -> item.id)
|
.mapToInt(item -> item.id)
|
||||||
.toArray();
|
.toArray();
|
||||||
|
|
||||||
log.debug("Loaded {} tradeable items", tradeableItems.length);
|
log.debug("Loaded {} tradeable items", tradeableItems.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ public class LootTrackerController
|
|||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping
|
@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);
|
SessionEntry e = auth.handle(request, response);
|
||||||
if (e == null)
|
if (e == null)
|
||||||
@@ -75,7 +75,7 @@ public class LootTrackerController
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return service.get(e.getUser(), count);
|
return service.get(e.getUser(), count, start);
|
||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping
|
@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_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 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 = "DELETE FROM kills WHERE accountId = :accountId";
|
||||||
private static final String DELETE_LOOT_ACCOUNT_EVENTID = "DELETE FROM kills WHERE accountId = :accountId AND eventId = :eventId";
|
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;
|
List<LootResult> lootResults;
|
||||||
|
|
||||||
@@ -128,6 +128,7 @@ public class LootTrackerService
|
|||||||
lootResults = con.createQuery(SELECT_LOOT_QUERY)
|
lootResults = con.createQuery(SELECT_LOOT_QUERY)
|
||||||
.addParameter("accountId", accountId)
|
.addParameter("accountId", accountId)
|
||||||
.addParameter("limit", limit)
|
.addParameter("limit", limit)
|
||||||
|
.addParameter("offset", offset)
|
||||||
.executeAndFetch(LootResult.class);
|
.executeAndFetch(LootResult.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +142,7 @@ public class LootTrackerService
|
|||||||
{
|
{
|
||||||
if (!gameItems.isEmpty())
|
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);
|
lootRecords.add(lootRecord);
|
||||||
|
|
||||||
gameItems = new ArrayList<>();
|
gameItems = new ArrayList<>();
|
||||||
@@ -156,7 +157,7 @@ public class LootTrackerService
|
|||||||
|
|
||||||
if (!gameItems.isEmpty())
|
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);
|
lootRecords.add(lootRecord);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,12 +35,12 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/osb/ge")
|
@RequestMapping("/osb/ge")
|
||||||
public class GrandExchangeController
|
public class OSBGrandExchangeController
|
||||||
{
|
{
|
||||||
private final GrandExchangeService grandExchangeService;
|
private final OSBGrandExchangeService grandExchangeService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public GrandExchangeController(GrandExchangeService grandExchangeService)
|
public OSBGrandExchangeController(OSBGrandExchangeService grandExchangeService)
|
||||||
{
|
{
|
||||||
this.grandExchangeService = grandExchangeService;
|
this.grandExchangeService = grandExchangeService;
|
||||||
}
|
}
|
||||||
@@ -40,7 +40,7 @@ import org.sql2o.Sql2o;
|
|||||||
|
|
||||||
@Service
|
@Service
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class GrandExchangeService
|
public class OSBGrandExchangeService
|
||||||
{
|
{
|
||||||
private static final String CREATE_GRAND_EXCHANGE_PRICES = "CREATE TABLE IF NOT EXISTS `osb_ge` (\n"
|
private static final String CREATE_GRAND_EXCHANGE_PRICES = "CREATE TABLE IF NOT EXISTS `osb_ge` (\n"
|
||||||
+ " `item_id` int(11) NOT NULL,\n"
|
+ " `item_id` int(11) NOT NULL,\n"
|
||||||
@@ -56,7 +56,7 @@ public class GrandExchangeService
|
|||||||
private final Sql2o sql2o;
|
private final Sql2o sql2o;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public GrandExchangeService(@Qualifier("Runelite SQL2O") Sql2o sql2o)
|
public OSBGrandExchangeService(@Qualifier("Runelite SQL2O") Sql2o sql2o)
|
||||||
{
|
{
|
||||||
this.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);
|
XpData xpEntityToXpData(XpEntity xpEntity);
|
||||||
|
|
||||||
|
@Mapping(target = "time", ignore = true)
|
||||||
|
|
||||||
@Mapping(source = "attack.experience", target = "attack_xp")
|
@Mapping(source = "attack.experience", target = "attack_xp")
|
||||||
@Mapping(source = "defence.experience", target = "defence_xp")
|
@Mapping(source = "defence.experience", target = "defence_xp")
|
||||||
@Mapping(source = "strength.experience", target = "strength_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.nio.charset.Charset;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.util.ArrayDeque;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.runelite.http.api.hiscore.HiscoreEndpoint;
|
import net.runelite.http.api.hiscore.HiscoreEndpoint;
|
||||||
@@ -50,8 +50,8 @@ import org.sql2o.Sql2o;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class XpTrackerService
|
public class XpTrackerService
|
||||||
{
|
{
|
||||||
private static final int QUEUE_LIMIT = 100_000;
|
private static final int QUEUE_LIMIT = 32768;
|
||||||
private static final Duration UPDATE_TIME = Duration.ofMinutes(5);
|
private static final int BLOOMFILTER_EXPECTED_INSERTIONS = 100_000;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier("Runelite XP Tracker SQL2O")
|
@Qualifier("Runelite XP Tracker SQL2O")
|
||||||
@@ -60,7 +60,7 @@ public class XpTrackerService
|
|||||||
@Autowired
|
@Autowired
|
||||||
private HiscoreService hiscoreService;
|
private HiscoreService hiscoreService;
|
||||||
|
|
||||||
private final Queue<String> usernameUpdateQueue = new ConcurrentLinkedDeque<>();
|
private final Queue<String> usernameUpdateQueue = new ArrayDeque<>();
|
||||||
private BloomFilter<String> usernameFilter = createFilter();
|
private BloomFilter<String> usernameFilter = createFilter();
|
||||||
|
|
||||||
public void update(String username) throws ExecutionException
|
public void update(String username) throws ExecutionException
|
||||||
@@ -76,13 +76,31 @@ public class XpTrackerService
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (usernameUpdateQueue.size() >= QUEUE_LIMIT)
|
try (Connection con = sql2o.open())
|
||||||
{
|
{
|
||||||
log.warn("Username update queue is full ({})", QUEUE_LIMIT);
|
PlayerEntity playerEntity = findOrCreatePlayer(con, username);
|
||||||
return;
|
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);
|
usernameFilter.put(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,13 +122,6 @@ public class XpTrackerService
|
|||||||
log.debug("Hiscore for {} already up to date", username);
|
log.debug("Hiscore for {} already up to date", username);
|
||||||
return;
|
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,"
|
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("construction_rank", hiscoreResult.getConstruction().getRank())
|
||||||
.addParameter("overall_rank", hiscoreResult.getOverall().getRank())
|
.addParameter("overall_rank", hiscoreResult.getOverall().getRank())
|
||||||
.executeUpdate();
|
.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.setId(id);
|
||||||
playerEntity.setName(username);
|
playerEntity.setName(username);
|
||||||
playerEntity.setTracked_since(now);
|
playerEntity.setTracked_since(now);
|
||||||
|
playerEntity.setLast_updated(now);
|
||||||
return playerEntity;
|
return playerEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,18 +237,21 @@ public class XpTrackerService
|
|||||||
@Scheduled(fixedDelay = 1000)
|
@Scheduled(fixedDelay = 1000)
|
||||||
public void update() throws ExecutionException
|
public void update() throws ExecutionException
|
||||||
{
|
{
|
||||||
String next = usernameUpdateQueue.poll();
|
String next;
|
||||||
|
synchronized (usernameUpdateQueue)
|
||||||
|
{
|
||||||
|
next = usernameUpdateQueue.poll();
|
||||||
|
}
|
||||||
|
|
||||||
if (next == null)
|
if (next == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
HiscoreResult hiscoreResult = hiscoreService.lookupUsername(next, HiscoreEndpoint.NORMAL);
|
update(next);
|
||||||
update(next, hiscoreResult);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Scheduled(fixedDelay = 3 * 60 * 60 * 1000) // 3 hours
|
@Scheduled(fixedDelay = 6 * 60 * 60 * 1000) // 6 hours
|
||||||
public void clearFilter()
|
public void clearFilter()
|
||||||
{
|
{
|
||||||
usernameFilter = createFilter();
|
usernameFilter = createFilter();
|
||||||
@@ -241,14 +261,47 @@ public class XpTrackerService
|
|||||||
{
|
{
|
||||||
final BloomFilter<String> filter = BloomFilter.create(
|
final BloomFilter<String> filter = BloomFilter.create(
|
||||||
Funnels.stringFunnel(Charset.defaultCharset()),
|
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;
|
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 Integer id;
|
||||||
private String name;
|
private String name;
|
||||||
private Instant tracked_since;
|
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
|
-- 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_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||||
@@ -26,6 +26,8 @@ CREATE TABLE `player` (
|
|||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
`name` varchar(32) NOT NULL,
|
`name` varchar(32) NOT NULL,
|
||||||
`tracked_since` timestamp NOT NULL DEFAULT current_timestamp(),
|
`tracked_since` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||||
|
`last_updated` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||||
|
`rank` int(11) DEFAULT NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
UNIQUE KEY `name` (`name`)
|
UNIQUE KEY `name` (`name`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||||
@@ -116,7 +118,7 @@ CREATE TABLE `xp` (
|
|||||||
`overall_rank` int(11) NOT NULL,
|
`overall_rank` int(11) NOT NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
UNIQUE KEY `player_time` (`player`,`time`),
|
UNIQUE KEY `player_time` (`player`,`time`),
|
||||||
INDEX `idx_time` (`time`),
|
KEY `idx_time` (`time`),
|
||||||
CONSTRAINT `fk_player` FOREIGN KEY (`player`) REFERENCES `player` (`id`)
|
CONSTRAINT `fk_player` FOREIGN KEY (`player`) REFERENCES `player` (`id`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
@@ -130,4 +132,4 @@ CREATE TABLE `xp` (
|
|||||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
/*!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.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -24,54 +24,20 @@
|
|||||||
*/
|
*/
|
||||||
package net.runelite.http.service;
|
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.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.boot.SpringApplication;
|
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
|
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
|
@Test
|
||||||
@Ignore
|
@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 (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
Thread.sleep(100L);
|
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>
|
<groupId>net.runelite</groupId>
|
||||||
<artifactId>runelite-parent</artifactId>
|
<artifactId>runelite-parent</artifactId>
|
||||||
<version>1.5.12-SNAPSHOT</version>
|
<version>1.5.14-SNAPSHOT</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
<name>RuneLite</name>
|
<name>RuneLite</name>
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>net.runelite</groupId>
|
<groupId>net.runelite</groupId>
|
||||||
<artifactId>runelite-parent</artifactId>
|
<artifactId>runelite-parent</artifactId>
|
||||||
<version>1.5.12-SNAPSHOT</version>
|
<version>1.5.14-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>protocol-api</artifactId>
|
<artifactId>protocol-api</artifactId>
|
||||||
|
|||||||
@@ -25,8 +25,10 @@
|
|||||||
package net.runelite.protocol.api.handshake;
|
package net.runelite.protocol.api.handshake;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class LoginHandshakePacket extends HandshakePacket
|
public class LoginHandshakePacket extends HandshakePacket
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@@ -26,9 +26,11 @@ package net.runelite.protocol.api.handshake;
|
|||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class UpdateHandshakePacket extends HandshakePacket
|
public class UpdateHandshakePacket extends HandshakePacket
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>net.runelite</groupId>
|
<groupId>net.runelite</groupId>
|
||||||
<artifactId>runelite-parent</artifactId>
|
<artifactId>runelite-parent</artifactId>
|
||||||
<version>1.5.12-SNAPSHOT</version>
|
<version>1.5.14-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>protocol</artifactId>
|
<artifactId>protocol</artifactId>
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>net.runelite</groupId>
|
<groupId>net.runelite</groupId>
|
||||||
<artifactId>runelite-parent</artifactId>
|
<artifactId>runelite-parent</artifactId>
|
||||||
<version>1.5.12-SNAPSHOT</version>
|
<version>1.5.14-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>runelite-api</artifactId>
|
<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 HERBLORE_POTIONMAKING = 363; //used for both herb and secondary
|
||||||
public static final int MAGIC_CHARGING_ORBS = 726;
|
public static final int MAGIC_CHARGING_ORBS = 726;
|
||||||
public static final int MAGIC_MAKE_TABLET = 4068;
|
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 BURYING_BONES = 827;
|
||||||
public static final int USING_GILDED_ALTAR = 3705;
|
public static final int USING_GILDED_ALTAR = 3705;
|
||||||
public static final int LOOKING_INTO = 832;
|
public static final int LOOKING_INTO = 832;
|
||||||
|
|||||||
@@ -1569,4 +1569,16 @@ public interface Client extends GameEngine
|
|||||||
int getRasterizer3D_clipMidY2();
|
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);
|
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
|
* @see net.runelite.api.model.Jarvis
|
||||||
*/
|
*/
|
||||||
Polygon getConvexHull();
|
Polygon getConvexHull();
|
||||||
|
Polygon getConvexHull2();
|
||||||
|
|
||||||
Renderable getRenderable();
|
Renderable getRenderable();
|
||||||
Renderable getRenderable2();
|
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;
|
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
|
* 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_ACTIVATED = 1197;
|
||||||
public static final int MINIMAP_ORB_XP_HOVERED = 1198;
|
public static final int MINIMAP_ORB_XP_HOVERED = 1198;
|
||||||
public static final int MINIMAP_ORB_XP_ACTIVATED_HOVERED = 1199;
|
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 OPTIONS_ZOOM_SLIDER_THUMB = 1201;
|
||||||
public static final int EMOTE_SIT_UP = 1202;
|
public static final int EMOTE_SIT_UP = 1202;
|
||||||
public static final int EMOTE_STAR_JUMP = 1203;
|
public static final int EMOTE_STAR_JUMP = 1203;
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ public enum VarClientStr
|
|||||||
{
|
{
|
||||||
CHATBOX_TYPED_TEXT(1),
|
CHATBOX_TYPED_TEXT(1),
|
||||||
INPUT_TEXT(22),
|
INPUT_TEXT(22),
|
||||||
|
PRIVATE_MESSAGE_TARGET(23),
|
||||||
RECENT_CLAN_CHAT(129);
|
RECENT_CLAN_CHAT(129);
|
||||||
|
|
||||||
private final int index;
|
private final int index;
|
||||||
|
|||||||
@@ -37,6 +37,10 @@ public enum VarPlayer
|
|||||||
ATTACK_STYLE(43),
|
ATTACK_STYLE(43),
|
||||||
QUEST_POINTS(101),
|
QUEST_POINTS(101),
|
||||||
IS_POISONED(102),
|
IS_POISONED(102),
|
||||||
|
/**
|
||||||
|
* Seems to start at 50(10 splash) and goes down by 1 every 30 seconds
|
||||||
|
*/
|
||||||
|
DISEASE_VALUE(456),
|
||||||
|
|
||||||
BANK_TAB(115),
|
BANK_TAB(115),
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,10 @@
|
|||||||
*/
|
*/
|
||||||
package net.runelite.api.coords;
|
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 lombok.Value;
|
||||||
import net.runelite.api.Client;
|
import net.runelite.api.Client;
|
||||||
import static net.runelite.api.Constants.CHUNK_SIZE;
|
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 client the client
|
||||||
* @param localPoint the local coordinate
|
* @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
|
* Rotate the coordinates in the chunk according to chunk rotation
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ public enum InputType
|
|||||||
RUNELITE_CHATBOX_PANEL(-3),
|
RUNELITE_CHATBOX_PANEL(-3),
|
||||||
RUNELITE(-2),
|
RUNELITE(-2),
|
||||||
NONE(0),
|
NONE(0),
|
||||||
|
PRIVATE_MESSAGE(6),
|
||||||
SEARCH(11);
|
SEARCH(11);
|
||||||
|
|
||||||
private final int type;
|
private final int type;
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ public interface Widget
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the current click configuration of the widget.
|
* Gets the current click configuration of the widget.
|
||||||
|
* @see WidgetConfig
|
||||||
*
|
*
|
||||||
* @see WidgetConfig
|
* @see WidgetConfig
|
||||||
*/
|
*/
|
||||||
@@ -551,6 +552,13 @@ public interface Widget
|
|||||||
*/
|
*/
|
||||||
void setOnMouseOverListener(Object... args);
|
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
|
* Sets a script to be ran when the mouse leaves the widget bounds
|
||||||
*
|
*
|
||||||
@@ -565,6 +573,20 @@ public interface Widget
|
|||||||
*/
|
*/
|
||||||
void setOnTimerListener(Object... args);
|
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
|
* If this widget has any listeners on it
|
||||||
*/
|
*/
|
||||||
@@ -769,4 +791,34 @@ public interface Widget
|
|||||||
* Sets if the rectangle is filled or just stroked
|
* Sets if the rectangle is filled or just stroked
|
||||||
*/
|
*/
|
||||||
void setFilled(boolean filled);
|
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;
|
package net.runelite.api.widgets;
|
||||||
|
|
||||||
|
import net.runelite.api.MenuAction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility class used for defining options to be used on the click mask
|
* Utility class used for defining options to be used on the click mask
|
||||||
* of a {@link Widget}.
|
* of a {@link Widget}.
|
||||||
@@ -36,12 +38,61 @@ public class WidgetConfig
|
|||||||
* Enables displaying a ninth option on a menu.
|
* Enables displaying a ninth option on a menu.
|
||||||
*/
|
*/
|
||||||
public static final int SHOW_MENU_OPTION_NINE = 1 << 9;
|
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.
|
* Controls whether or not a widget can have another dragged onto it.
|
||||||
*/
|
*/
|
||||||
public static final int DRAG_ON = 1 << 17;
|
public static final int DRAG_ON = 1 << 17;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controls whether or not a widget can be dragged around.
|
* Controls whether or not a widget can be dragged around.
|
||||||
*/
|
*/
|
||||||
public static final int DRAG = 1 << 20;
|
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 SKOTIZO_GROUP_ID = 308;
|
||||||
public static final int ENTERING_HOUSE_GROUP_ID = 71;
|
public static final int ENTERING_HOUSE_GROUP_ID = 71;
|
||||||
public static final int FULLSCREEN_MAP_GROUP_ID = 165;
|
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
|
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 TOGGLE_RUN_ORB = 22; // Has the "Toggle run" name
|
||||||
static final int RUN_ORB_TEXT = 23;
|
static final int RUN_ORB_TEXT = 23;
|
||||||
static final int SPEC_ORB = 28;
|
static final int SPEC_ORB = 28;
|
||||||
|
static final int WORLDMAP_ORB = 40;
|
||||||
}
|
}
|
||||||
|
|
||||||
static class LoginClickToPlayScreen
|
static class LoginClickToPlayScreen
|
||||||
@@ -747,4 +750,11 @@ public class WidgetID
|
|||||||
{
|
{
|
||||||
static final int ROOT = 25;
|
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_RUN_ORB_TEXT(WidgetID.MINIMAP_GROUP_ID, WidgetID.Minimap.RUN_ORB_TEXT),
|
||||||
MINIMAP_HEALTH_ORB(WidgetID.MINIMAP_GROUP_ID, WidgetID.Minimap.HEALTH_ORB),
|
MINIMAP_HEALTH_ORB(WidgetID.MINIMAP_GROUP_ID, WidgetID.Minimap.HEALTH_ORB),
|
||||||
MINIMAP_SPEC_ORB(WidgetID.MINIMAP_GROUP_ID, WidgetID.Minimap.SPEC_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(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),
|
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),
|
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 groupId;
|
||||||
private final int childId;
|
private final int childId;
|
||||||
|
|||||||
@@ -27,9 +27,12 @@ package net.runelite.api.widgets;
|
|||||||
public final class WidgetType
|
public final class WidgetType
|
||||||
{
|
{
|
||||||
public static final int LAYER = 0;
|
public static final int LAYER = 0;
|
||||||
|
public static final int INVENTORY = 2;
|
||||||
public static final int RECTANGLE = 3;
|
public static final int RECTANGLE = 3;
|
||||||
public static final int TEXT = 4;
|
public static final int TEXT = 4;
|
||||||
public static final int GRAPHIC = 5;
|
public static final int GRAPHIC = 5;
|
||||||
public static final int MODEL = 6;
|
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;
|
public static final int LINE = 9;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>net.runelite</groupId>
|
<groupId>net.runelite</groupId>
|
||||||
<artifactId>runelite-parent</artifactId>
|
<artifactId>runelite-parent</artifactId>
|
||||||
<version>1.5.12-SNAPSHOT</version>
|
<version>1.5.14-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>client</artifactId>
|
<artifactId>client</artifactId>
|
||||||
|
|||||||
@@ -183,9 +183,9 @@ public class RuneLite
|
|||||||
System.exit(0);
|
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;
|
boolean assertions = false;
|
||||||
assert assertions = true;
|
assert assertions = true;
|
||||||
|
|||||||
@@ -43,8 +43,11 @@ import java.lang.reflect.Modifier;
|
|||||||
import java.lang.reflect.Proxy;
|
import java.lang.reflect.Proxy;
|
||||||
import java.nio.channels.FileLock;
|
import java.nio.channels.FileLock;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -70,6 +73,7 @@ import net.runelite.http.api.config.Configuration;
|
|||||||
public class ConfigManager
|
public class ConfigManager
|
||||||
{
|
{
|
||||||
private static final String SETTINGS_FILE_NAME = "settings.properties";
|
private static final String SETTINGS_FILE_NAME = "settings.properties";
|
||||||
|
private static final DateFormat TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
EventBus eventBus;
|
EventBus eventBus;
|
||||||
@@ -111,12 +115,17 @@ public class ConfigManager
|
|||||||
load(); // load profile specific config
|
load(); // load profile specific config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private File getLocalPropertiesFile()
|
||||||
|
{
|
||||||
|
return new File(RuneLite.RUNELITE_DIR, SETTINGS_FILE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
private File getPropertiesFile()
|
private File getPropertiesFile()
|
||||||
{
|
{
|
||||||
// Sessions that aren't logged in have no username
|
// Sessions that aren't logged in have no username
|
||||||
if (session == null || session.getUsername() == null)
|
if (session == null || session.getUsername() == null)
|
||||||
{
|
{
|
||||||
return new File(RuneLite.RUNELITE_DIR, SETTINGS_FILE_NAME);
|
return getLocalPropertiesFile();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -158,7 +167,13 @@ public class ConfigManager
|
|||||||
for (ConfigEntry entry : configuration.getConfig())
|
for (ConfigEntry entry : configuration.getConfig())
|
||||||
{
|
{
|
||||||
log.debug("Loading configuration value from client {}: {}", entry.getKey(), entry.getValue());
|
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 groupName = split[0];
|
||||||
final String key = split[1];
|
final String key = split[1];
|
||||||
final String value = entry.getValue();
|
final String value = entry.getValue();
|
||||||
@@ -174,7 +189,7 @@ public class ConfigManager
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
saveToFile();
|
saveToFile(propertiesFile);
|
||||||
|
|
||||||
log.debug("Updated configuration on disk with the latest version");
|
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()
|
private synchronized void loadFromFile()
|
||||||
{
|
{
|
||||||
properties.clear();
|
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();
|
propertiesFile.getParentFile().mkdirs();
|
||||||
|
|
||||||
@@ -294,8 +378,6 @@ public class ConfigManager
|
|||||||
|
|
||||||
public void setConfiguration(String groupName, String key, String value)
|
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);
|
String oldValue = (String) properties.setProperty(groupName + "." + key, value);
|
||||||
|
|
||||||
if (Objects.equals(oldValue, value))
|
if (Objects.equals(oldValue, value))
|
||||||
@@ -303,6 +385,8 @@ public class ConfigManager
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.debug("Setting configuration value for {}.{} to {}", groupName, key, value);
|
||||||
|
|
||||||
synchronized (pendingChanges)
|
synchronized (pendingChanges)
|
||||||
{
|
{
|
||||||
pendingChanges.put(groupName + "." + key, value);
|
pendingChanges.put(groupName + "." + key, value);
|
||||||
@@ -312,7 +396,7 @@ public class ConfigManager
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
saveToFile();
|
saveToFile(propertiesFile);
|
||||||
}
|
}
|
||||||
catch (IOException ex)
|
catch (IOException ex)
|
||||||
{
|
{
|
||||||
@@ -337,8 +421,6 @@ public class ConfigManager
|
|||||||
|
|
||||||
public void unsetConfiguration(String groupName, String key)
|
public void unsetConfiguration(String groupName, String key)
|
||||||
{
|
{
|
||||||
log.debug("Unsetting configuration value for {}.{}", groupName, key);
|
|
||||||
|
|
||||||
String oldValue = (String) properties.remove(groupName + "." + key);
|
String oldValue = (String) properties.remove(groupName + "." + key);
|
||||||
|
|
||||||
if (oldValue == null)
|
if (oldValue == null)
|
||||||
@@ -346,6 +428,8 @@ public class ConfigManager
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.debug("Unsetting configuration value for {}.{}", groupName, key);
|
||||||
|
|
||||||
synchronized (pendingChanges)
|
synchronized (pendingChanges)
|
||||||
{
|
{
|
||||||
pendingChanges.put(groupName + "." + key, null);
|
pendingChanges.put(groupName + "." + key, null);
|
||||||
@@ -355,7 +439,7 @@ public class ConfigManager
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
saveToFile();
|
saveToFile(propertiesFile);
|
||||||
}
|
}
|
||||||
catch (IOException ex)
|
catch (IOException ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ public class DiscordService implements AutoCloseable
|
|||||||
discordRPC = DiscordRPC.INSTANCE;
|
discordRPC = DiscordRPC.INSTANCE;
|
||||||
discordEventHandlers = new DiscordEventHandlers();
|
discordEventHandlers = new DiscordEventHandlers();
|
||||||
}
|
}
|
||||||
catch (UnsatisfiedLinkError e)
|
catch (Error e)
|
||||||
{
|
{
|
||||||
log.warn("Failed to load Discord library, Discord support will be disabled.");
|
log.warn("Failed to load Discord library, Discord support will be disabled.");
|
||||||
}
|
}
|
||||||
@@ -150,9 +150,12 @@ public class DiscordService implements AutoCloseable
|
|||||||
? "default"
|
? "default"
|
||||||
: discordPresence.getLargeImageKey();
|
: discordPresence.getLargeImageKey();
|
||||||
discordRichPresence.largeImageText = discordPresence.getLargeImageText();
|
discordRichPresence.largeImageText = discordPresence.getLargeImageText();
|
||||||
discordRichPresence.smallImageKey = Strings.isNullOrEmpty(discordPresence.getSmallImageKey())
|
|
||||||
? "default"
|
if (!Strings.isNullOrEmpty(discordPresence.getSmallImageKey()))
|
||||||
: discordPresence.getSmallImageKey();
|
{
|
||||||
|
discordRichPresence.smallImageKey = discordPresence.getSmallImageKey();
|
||||||
|
}
|
||||||
|
|
||||||
discordRichPresence.smallImageText = discordPresence.getSmallImageText();
|
discordRichPresence.smallImageText = discordPresence.getSmallImageText();
|
||||||
discordRichPresence.partyId = discordPresence.getPartyId();
|
discordRichPresence.partyId = discordPresence.getPartyId();
|
||||||
discordRichPresence.partySize = discordPresence.getPartySize();
|
discordRichPresence.partySize = discordPresence.getPartySize();
|
||||||
|
|||||||
@@ -25,8 +25,10 @@
|
|||||||
package net.runelite.client.events;
|
package net.runelite.client.events;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public abstract class ChatboxInput extends ChatInput
|
public abstract class ChatboxInput extends ChatInput
|
||||||
{
|
{
|
||||||
private final String value;
|
private final String value;
|
||||||
|
|||||||
@@ -25,8 +25,10 @@
|
|||||||
package net.runelite.client.events;
|
package net.runelite.client.events;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public abstract class PrivateMessageInput extends ChatInput
|
public abstract class PrivateMessageInput extends ChatInput
|
||||||
{
|
{
|
||||||
private final String target;
|
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());
|
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
|
* 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.common.cache.CacheBuilder;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@@ -36,11 +37,14 @@ import javax.swing.ImageIcon;
|
|||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.runelite.api.Client;
|
import net.runelite.api.Client;
|
||||||
import net.runelite.api.GameState;
|
import net.runelite.api.GameState;
|
||||||
import net.runelite.api.SpritePixels;
|
import net.runelite.api.SpritePixels;
|
||||||
import net.runelite.client.callback.ClientThread;
|
import net.runelite.client.callback.ClientThread;
|
||||||
|
import net.runelite.client.util.ImageUtil;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
@Singleton
|
@Singleton
|
||||||
public class SpriteManager
|
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;
|
package net.runelite.client.game.chatbox;
|
||||||
|
|
||||||
|
import com.google.common.base.Strings;
|
||||||
|
import com.google.common.primitives.Ints;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
import java.awt.Point;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
import java.awt.Toolkit;
|
import java.awt.Toolkit;
|
||||||
import java.awt.datatransfer.DataFlavor;
|
import java.awt.datatransfer.DataFlavor;
|
||||||
@@ -33,21 +36,25 @@ import java.awt.datatransfer.UnsupportedFlavorException;
|
|||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.IntPredicate;
|
import java.util.function.IntPredicate;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.function.ToIntFunction;
|
import java.util.function.ToIntFunction;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.runelite.api.FontTypeFace;
|
|
||||||
import net.runelite.api.FontID;
|
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.JavaScriptCallback;
|
||||||
import net.runelite.api.widgets.Widget;
|
import net.runelite.api.widgets.Widget;
|
||||||
import net.runelite.api.widgets.WidgetPositionMode;
|
import net.runelite.api.widgets.WidgetPositionMode;
|
||||||
import net.runelite.api.widgets.WidgetSizeMode;
|
import net.runelite.api.widgets.WidgetSizeMode;
|
||||||
import net.runelite.api.widgets.WidgetTextAlignment;
|
import net.runelite.api.widgets.WidgetTextAlignment;
|
||||||
|
import net.runelite.api.widgets.WidgetType;
|
||||||
import net.runelite.client.callback.ClientThread;
|
import net.runelite.client.callback.ClientThread;
|
||||||
import net.runelite.client.input.KeyListener;
|
import net.runelite.client.input.KeyListener;
|
||||||
import net.runelite.client.input.MouseListener;
|
import net.runelite.client.input.MouseListener;
|
||||||
@@ -57,6 +64,7 @@ import net.runelite.client.util.Text;
|
|||||||
public class ChatboxTextInput extends ChatboxInput implements KeyListener, MouseListener
|
public class ChatboxTextInput extends ChatboxInput implements KeyListener, MouseListener
|
||||||
{
|
{
|
||||||
private static final int CURSOR_FLASH_RATE_MILLIS = 1000;
|
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 ChatboxPanelManager chatboxPanelManager;
|
||||||
private final ClientThread clientThread;
|
private final ClientThread clientThread;
|
||||||
@@ -66,13 +74,24 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
|
|||||||
return i -> i >= 32 && i < 127;
|
return i -> i >= 32 && i < 127;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
private static class Line
|
||||||
|
{
|
||||||
|
private final int start;
|
||||||
|
private final int end;
|
||||||
|
private final String text;
|
||||||
|
}
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private String prompt;
|
private String prompt;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private int lines;
|
||||||
|
|
||||||
private StringBuffer value = new StringBuffer();
|
private StringBuffer value = new StringBuffer();
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private int cursor = 0;
|
private int cursorStart = 0;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private int cursorEnd = 0;
|
private int cursorEnd = 0;
|
||||||
@@ -95,12 +114,14 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
|
|||||||
@Getter
|
@Getter
|
||||||
private int fontID = FontID.QUILL_8;
|
private int fontID = FontID.QUILL_8;
|
||||||
|
|
||||||
// This is a lambda so I can have atomic updates for it's captures
|
@Getter
|
||||||
private ToIntFunction<MouseEvent> getCharOffset = null;
|
|
||||||
private Predicate<MouseEvent> isInBounds = null;
|
|
||||||
|
|
||||||
private boolean built = false;
|
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
|
@Inject
|
||||||
protected ChatboxTextInput(ChatboxPanelManager chatboxPanelManager, ClientThread clientThread)
|
protected ChatboxTextInput(ChatboxPanelManager chatboxPanelManager, ClientThread clientThread)
|
||||||
{
|
{
|
||||||
@@ -108,6 +129,16 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
|
|||||||
this.clientThread = clientThread;
|
this.clientThread = clientThread;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ChatboxTextInput lines(int lines)
|
||||||
|
{
|
||||||
|
this.lines = lines;
|
||||||
|
if (built)
|
||||||
|
{
|
||||||
|
clientThread.invoke(this::update);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public ChatboxTextInput prompt(String prompt)
|
public ChatboxTextInput prompt(String prompt)
|
||||||
{
|
{
|
||||||
this.prompt = prompt;
|
this.prompt = prompt;
|
||||||
@@ -157,7 +188,7 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
|
|||||||
end = v;
|
end = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.cursor = start;
|
this.cursorStart = start;
|
||||||
this.cursorEnd = end;
|
this.cursorEnd = end;
|
||||||
|
|
||||||
if (built)
|
if (built)
|
||||||
@@ -209,7 +240,6 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
|
|||||||
|
|
||||||
protected void update()
|
protected void update()
|
||||||
{
|
{
|
||||||
this.built = true;
|
|
||||||
Widget container = chatboxPanelManager.getContainerWidget();
|
Widget container = chatboxPanelManager.getContainerWidget();
|
||||||
container.deleteAllChildren();
|
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)
|
protected void buildEdit(int x, int y, int w, int h)
|
||||||
{
|
{
|
||||||
|
final List<Line> editLines = new ArrayList<>();
|
||||||
|
|
||||||
Widget container = chatboxPanelManager.getContainerWidget();
|
Widget container = chatboxPanelManager.getContainerWidget();
|
||||||
|
|
||||||
String lt = Text.escapeJagex(value.substring(0, this.cursor));
|
final Widget cursor = container.createChild(-1, WidgetType.RECTANGLE);
|
||||||
String mt = Text.escapeJagex(value.substring(this.cursor, this.cursorEnd));
|
long start = System.currentTimeMillis();
|
||||||
String rt = Text.escapeJagex(value.substring(this.cursorEnd));
|
cursor.setOnTimerListener((JavaScriptCallback) ev ->
|
||||||
|
{
|
||||||
Widget leftText = container.createChild(-1, WidgetType.TEXT);
|
boolean on = (System.currentTimeMillis() - start) % CURSOR_FLASH_RATE_MILLIS > (CURSOR_FLASH_RATE_MILLIS / 2);
|
||||||
Widget cursor = container.createChild(-1, WidgetType.RECTANGLE);
|
cursor.setOpacity(on ? 255 : 0);
|
||||||
Widget middleText = container.createChild(-1, WidgetType.TEXT);
|
});
|
||||||
Widget rightText = container.createChild(-1, WidgetType.TEXT);
|
cursor.setTextColor(0xFFFFFF);
|
||||||
|
cursor.setHasListener(true);
|
||||||
leftText.setFontId(fontID);
|
cursor.setFilled(true);
|
||||||
FontTypeFace font = leftText.getFont();
|
cursor.setFontId(fontID);
|
||||||
|
|
||||||
|
FontTypeFace font = cursor.getFont();
|
||||||
if (h <= 0)
|
if (h <= 0)
|
||||||
{
|
{
|
||||||
h = font.getBaseline();
|
h = font.getBaseline();
|
||||||
}
|
}
|
||||||
|
|
||||||
int ltw = font.getTextWidth(lt);
|
final int oy = y;
|
||||||
int mtw = font.getTextWidth(mt);
|
final int ox = x;
|
||||||
int rtw = font.getTextWidth(rt);
|
final int oh = h;
|
||||||
|
|
||||||
int fullWidth = ltw + mtw + rtw;
|
int breakIndex = -1;
|
||||||
|
final StringBuilder sb = new StringBuilder();
|
||||||
int ox = x;
|
for (int i = 0; i < value.length(); i++)
|
||||||
if (w > 0)
|
|
||||||
{
|
{
|
||||||
x += (w - fullWidth) / 2;
|
int count = i - sb.length();
|
||||||
}
|
final String c = value.charAt(i) + "";
|
||||||
|
sb.append(c);
|
||||||
int ltx = x;
|
if (BREAK_MATCHER.matcher(c).matches())
|
||||||
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 ->
|
|
||||||
{
|
{
|
||||||
boolean on = (System.currentTimeMillis() - start) % CURSOR_FLASH_RATE_MILLIS > (CURSOR_FLASH_RATE_MILLIS / 2);
|
breakIndex = sb.length();
|
||||||
cursor.setOpacity(on ? 255 : 0);
|
}
|
||||||
});
|
|
||||||
cursor.setHasListener(true);
|
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);
|
Rectangle bounds = new Rectangle(container.getCanvasLocation().getX() + container.getWidth(), y, 0, editLines.size() * oh);
|
||||||
middleText.setFontId(fontID);
|
for (int i = 0; i < editLines.size() || i == 0; i++)
|
||||||
middleText.setOriginalX(mtx);
|
{
|
||||||
middleText.setOriginalY(y);
|
final Line line = editLines.size() > 0 ? editLines.get(i) : new Line(0, 0, "");
|
||||||
middleText.setOriginalWidth(mtw);
|
final String text = line.text;
|
||||||
middleText.setOriginalHeight(h);
|
final int len = text.length();
|
||||||
middleText.setTextColor(0xFFFFFF);
|
|
||||||
middleText.revalidate();
|
|
||||||
|
|
||||||
rightText.setText(rt);
|
String lt = Text.escapeJagex(text);
|
||||||
rightText.setFontId(fontID);
|
String mt = "";
|
||||||
rightText.setOriginalX(rtx);
|
String rt = "";
|
||||||
rightText.setOriginalY(y);
|
|
||||||
rightText.setOriginalWidth(rtw);
|
final boolean isStartLine = cursorOnLine(cursorStart, line.start, line.end)
|
||||||
rightText.setOriginalHeight(h);
|
|| (cursorOnLine(cursorStart, line.start, line.end + 1) && i == editLines.size() - 1);
|
||||||
rightText.revalidate();
|
|
||||||
|
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();
|
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(new Point(ev.getX() - ccl.getX(), ev.getY() - ccl.getY()));
|
||||||
isInBounds = ev -> bounds.contains(ev.getPoint());
|
getPointCharOffset = p ->
|
||||||
getCharOffset = ev ->
|
|
||||||
{
|
{
|
||||||
if (fullWidth <= 0)
|
if (bounds.width <= 0)
|
||||||
{
|
{
|
||||||
return 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
|
// `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--)
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (charIndex < 0)
|
charIndex = Ints.constrainToRange(charIndex, 0, tsValue.length());
|
||||||
|
return line.start + charIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
getLineOffset = code ->
|
||||||
|
{
|
||||||
|
if (editLines.size() < 2)
|
||||||
{
|
{
|
||||||
charIndex = 0;
|
return cursorStart;
|
||||||
}
|
|
||||||
if (charIndex > tsValue.length())
|
|
||||||
{
|
|
||||||
charIndex = tsValue.length();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
@Override
|
||||||
protected void open()
|
protected void open()
|
||||||
{
|
{
|
||||||
|
this.built = true;
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -398,12 +584,12 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
|
|||||||
char c = e.getKeyChar();
|
char c = e.getKeyChar();
|
||||||
if (charValidator.test(c))
|
if (charValidator.test(c))
|
||||||
{
|
{
|
||||||
if (cursor != cursorEnd)
|
if (cursorStart != cursorEnd)
|
||||||
{
|
{
|
||||||
value.delete(cursor, cursorEnd);
|
value.delete(cursorStart, cursorEnd);
|
||||||
}
|
}
|
||||||
value.insert(cursor, c);
|
value.insert(cursorStart, c);
|
||||||
cursorAt(cursor + 1);
|
cursorAt(cursorStart + 1);
|
||||||
if (onChanged != null)
|
if (onChanged != null)
|
||||||
{
|
{
|
||||||
onChanged.accept(getValue());
|
onChanged.accept(getValue());
|
||||||
@@ -421,13 +607,13 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
|
|||||||
{
|
{
|
||||||
case KeyEvent.VK_X:
|
case KeyEvent.VK_X:
|
||||||
case KeyEvent.VK_C:
|
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)
|
if (code == KeyEvent.VK_X)
|
||||||
{
|
{
|
||||||
value.delete(cursor, cursorEnd);
|
value.delete(cursorStart, cursorEnd);
|
||||||
cursorAt(cursor);
|
cursorAt(cursorStart);
|
||||||
}
|
}
|
||||||
Toolkit.getDefaultToolkit()
|
Toolkit.getDefaultToolkit()
|
||||||
.getSystemClipboard()
|
.getSystemClipboard()
|
||||||
@@ -441,20 +627,20 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
|
|||||||
.getSystemClipboard()
|
.getSystemClipboard()
|
||||||
.getData(DataFlavor.stringFlavor)
|
.getData(DataFlavor.stringFlavor)
|
||||||
.toString();
|
.toString();
|
||||||
if (cursor != cursorEnd)
|
if (cursorStart != cursorEnd)
|
||||||
{
|
{
|
||||||
value.delete(cursor, cursorEnd);
|
value.delete(cursorStart, cursorEnd);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < s.length(); i++)
|
for (int i = 0; i < s.length(); i++)
|
||||||
{
|
{
|
||||||
char ch = s.charAt(i);
|
char ch = s.charAt(i);
|
||||||
if (charValidator.test(ch))
|
if (charValidator.test(ch))
|
||||||
{
|
{
|
||||||
value.insert(cursor, ch);
|
value.insert(cursorStart, ch);
|
||||||
cursor++;
|
cursorStart++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cursorAt(cursor);
|
cursorAt(cursorStart);
|
||||||
if (onChanged != null)
|
if (onChanged != null)
|
||||||
{
|
{
|
||||||
onChanged.accept(getValue());
|
onChanged.accept(getValue());
|
||||||
@@ -468,13 +654,13 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int newPos = cursor;
|
int newPos = cursorStart;
|
||||||
if (ev.isShiftDown())
|
if (ev.isShiftDown())
|
||||||
{
|
{
|
||||||
if (selectionEnd == -1 || selectionStart == -1)
|
if (selectionEnd == -1 || selectionStart == -1)
|
||||||
{
|
{
|
||||||
selectionStart = cursor;
|
selectionStart = cursorStart;
|
||||||
selectionEnd = cursor;
|
selectionEnd = cursorStart;
|
||||||
}
|
}
|
||||||
newPos = selectionEnd;
|
newPos = selectionEnd;
|
||||||
}
|
}
|
||||||
@@ -486,20 +672,20 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
|
|||||||
switch (code)
|
switch (code)
|
||||||
{
|
{
|
||||||
case KeyEvent.VK_DELETE:
|
case KeyEvent.VK_DELETE:
|
||||||
if (cursor != cursorEnd)
|
if (cursorStart != cursorEnd)
|
||||||
{
|
{
|
||||||
value.delete(cursor, cursorEnd);
|
value.delete(cursorStart, cursorEnd);
|
||||||
cursorAt(cursor);
|
cursorAt(cursorStart);
|
||||||
if (onChanged != null)
|
if (onChanged != null)
|
||||||
{
|
{
|
||||||
onChanged.accept(getValue());
|
onChanged.accept(getValue());
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (cursor < value.length())
|
if (cursorStart < value.length())
|
||||||
{
|
{
|
||||||
value.deleteCharAt(cursor);
|
value.deleteCharAt(cursorStart);
|
||||||
cursorAt(cursor);
|
cursorAt(cursorStart);
|
||||||
if (onChanged != null)
|
if (onChanged != null)
|
||||||
{
|
{
|
||||||
onChanged.accept(getValue());
|
onChanged.accept(getValue());
|
||||||
@@ -507,20 +693,20 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case KeyEvent.VK_BACK_SPACE:
|
case KeyEvent.VK_BACK_SPACE:
|
||||||
if (cursor != cursorEnd)
|
if (cursorStart != cursorEnd)
|
||||||
{
|
{
|
||||||
value.delete(cursor, cursorEnd);
|
value.delete(cursorStart, cursorEnd);
|
||||||
cursorAt(cursor);
|
cursorAt(cursorStart);
|
||||||
if (onChanged != null)
|
if (onChanged != null)
|
||||||
{
|
{
|
||||||
onChanged.accept(getValue());
|
onChanged.accept(getValue());
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (cursor > 0)
|
if (cursorStart > 0)
|
||||||
{
|
{
|
||||||
value.deleteCharAt(cursor - 1);
|
value.deleteCharAt(cursorStart - 1);
|
||||||
cursorAt(cursor - 1);
|
cursorAt(cursorStart - 1);
|
||||||
if (onChanged != null)
|
if (onChanged != null)
|
||||||
{
|
{
|
||||||
onChanged.accept(getValue());
|
onChanged.accept(getValue());
|
||||||
@@ -535,6 +721,14 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
|
|||||||
ev.consume();
|
ev.consume();
|
||||||
newPos++;
|
newPos++;
|
||||||
break;
|
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:
|
case KeyEvent.VK_HOME:
|
||||||
ev.consume();
|
ev.consume();
|
||||||
newPos = 0;
|
newPos = 0;
|
||||||
@@ -553,9 +747,9 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
|
|||||||
return;
|
return;
|
||||||
case KeyEvent.VK_ESCAPE:
|
case KeyEvent.VK_ESCAPE:
|
||||||
ev.consume();
|
ev.consume();
|
||||||
if (cursor != cursorEnd)
|
if (cursorStart != cursorEnd)
|
||||||
{
|
{
|
||||||
cursorAt(cursor);
|
cursorAt(cursorStart);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
chatboxPanelManager.close();
|
chatboxPanelManager.close();
|
||||||
@@ -602,16 +796,16 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
|
|||||||
}
|
}
|
||||||
if (isInBounds == null || !isInBounds.test(mouseEvent))
|
if (isInBounds == null || !isInBounds.test(mouseEvent))
|
||||||
{
|
{
|
||||||
if (cursor != cursorEnd)
|
if (cursorStart != cursorEnd)
|
||||||
{
|
{
|
||||||
selectionStart = -1;
|
selectionStart = -1;
|
||||||
selectionEnd = -1;
|
selectionEnd = -1;
|
||||||
cursorAt(getCharOffset.applyAsInt(mouseEvent));
|
cursorAt(getCharOffset(mouseEvent));
|
||||||
}
|
}
|
||||||
return mouseEvent;
|
return mouseEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nco = getCharOffset.applyAsInt(mouseEvent);
|
int nco = getCharOffset(mouseEvent);
|
||||||
|
|
||||||
if (mouseEvent.isShiftDown() && selectionEnd != -1)
|
if (mouseEvent.isShiftDown() && selectionEnd != -1)
|
||||||
{
|
{
|
||||||
@@ -653,7 +847,7 @@ public class ChatboxTextInput extends ChatboxInput implements KeyListener, Mouse
|
|||||||
return mouseEvent;
|
return mouseEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nco = getCharOffset.applyAsInt(mouseEvent);
|
int nco = getCharOffset(mouseEvent);
|
||||||
if (selectionStart != -1)
|
if (selectionStart != -1)
|
||||||
{
|
{
|
||||||
selectionEnd = nco;
|
selectionEnd = nco;
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import net.runelite.api.Client;
|
|||||||
import net.runelite.api.Point;
|
import net.runelite.api.Point;
|
||||||
import net.runelite.api.Tile;
|
import net.runelite.api.Tile;
|
||||||
import net.runelite.api.coords.LocalPoint;
|
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.Overlay;
|
||||||
import net.runelite.client.ui.overlay.OverlayLayer;
|
import net.runelite.client.ui.overlay.OverlayLayer;
|
||||||
import net.runelite.client.ui.overlay.OverlayPosition;
|
import net.runelite.client.ui.overlay.OverlayPosition;
|
||||||
@@ -44,6 +45,7 @@ import net.runelite.client.ui.overlay.OverlayUtil;
|
|||||||
class AgilityOverlay extends Overlay
|
class AgilityOverlay extends Overlay
|
||||||
{
|
{
|
||||||
private static final int MAX_DISTANCE = 2350;
|
private static final int MAX_DISTANCE = 2350;
|
||||||
|
private static final Color SHORTCUT_HIGH_LEVEL_COLOR = Color.ORANGE;
|
||||||
|
|
||||||
private final Client client;
|
private final Client client;
|
||||||
private final AgilityPlugin plugin;
|
private final AgilityPlugin plugin;
|
||||||
@@ -66,14 +68,15 @@ class AgilityOverlay extends Overlay
|
|||||||
LocalPoint playerLocation = client.getLocalPlayer().getLocalLocation();
|
LocalPoint playerLocation = client.getLocalPlayer().getLocalLocation();
|
||||||
Point mousePosition = client.getMouseCanvasPosition();
|
Point mousePosition = client.getMouseCanvasPosition();
|
||||||
final List<Tile> marksOfGrace = plugin.getMarksOfGrace();
|
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())
|
Obstacles.TRAP_OBSTACLE_IDS.contains(object.getId()) && !config.showTrapOverlay())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Tile tile = obstacle.getTile();
|
||||||
if (tile.getPlane() == client.getPlane()
|
if (tile.getPlane() == client.getPlane()
|
||||||
&& object.getLocalLocation().distanceTo(playerLocation) < MAX_DISTANCE)
|
&& object.getLocalLocation().distanceTo(playerLocation) < MAX_DISTANCE)
|
||||||
{
|
{
|
||||||
@@ -87,11 +90,11 @@ class AgilityOverlay extends Overlay
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Area objectClickbox = object.getClickbox();
|
Area objectClickbox = object.getClickbox();
|
||||||
if (objectClickbox != null)
|
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())
|
if (config.highlightMarks() && !marksOfGrace.isEmpty())
|
||||||
{
|
{
|
||||||
configColor = config.getMarkColor();
|
configColor = config.getMarkColor();
|
||||||
|
|||||||
@@ -38,10 +38,12 @@ import net.runelite.api.Item;
|
|||||||
import net.runelite.api.ItemID;
|
import net.runelite.api.ItemID;
|
||||||
import static net.runelite.api.ItemID.AGILITY_ARENA_TICKET;
|
import static net.runelite.api.ItemID.AGILITY_ARENA_TICKET;
|
||||||
import net.runelite.api.Player;
|
import net.runelite.api.Player;
|
||||||
|
import net.runelite.api.Skill;
|
||||||
import static net.runelite.api.Skill.AGILITY;
|
import static net.runelite.api.Skill.AGILITY;
|
||||||
import net.runelite.api.Tile;
|
import net.runelite.api.Tile;
|
||||||
import net.runelite.api.TileObject;
|
import net.runelite.api.TileObject;
|
||||||
import net.runelite.api.coords.WorldPoint;
|
import net.runelite.api.coords.WorldPoint;
|
||||||
|
import net.runelite.api.events.BoostedLevelChanged;
|
||||||
import net.runelite.api.events.ConfigChanged;
|
import net.runelite.api.events.ConfigChanged;
|
||||||
import net.runelite.api.events.DecorativeObjectChanged;
|
import net.runelite.api.events.DecorativeObjectChanged;
|
||||||
import net.runelite.api.events.DecorativeObjectDespawned;
|
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.Notifier;
|
||||||
import net.runelite.client.config.ConfigManager;
|
import net.runelite.client.config.ConfigManager;
|
||||||
import net.runelite.client.eventbus.Subscribe;
|
import net.runelite.client.eventbus.Subscribe;
|
||||||
|
import net.runelite.client.game.AgilityShortcut;
|
||||||
import net.runelite.client.game.ItemManager;
|
import net.runelite.client.game.ItemManager;
|
||||||
import net.runelite.client.plugins.Plugin;
|
import net.runelite.client.plugins.Plugin;
|
||||||
import net.runelite.client.plugins.PluginDescriptor;
|
import net.runelite.client.plugins.PluginDescriptor;
|
||||||
@@ -80,7 +83,7 @@ public class AgilityPlugin extends Plugin
|
|||||||
private static final int AGILITY_ARENA_REGION_ID = 11157;
|
private static final int AGILITY_ARENA_REGION_ID = 11157;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final Map<TileObject, Tile> obstacles = new HashMap<>();
|
private final Map<TileObject, Obstacle> obstacles = new HashMap<>();
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final List<Tile> marksOfGrace = new ArrayList<>();
|
private final List<Tile> marksOfGrace = new ArrayList<>();
|
||||||
@@ -115,6 +118,9 @@ public class AgilityPlugin extends Plugin
|
|||||||
private int lastAgilityXp;
|
private int lastAgilityXp;
|
||||||
private WorldPoint lastArenaTicketPosition;
|
private WorldPoint lastArenaTicketPosition;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private int agilityLevel;
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
AgilityConfig getConfig(ConfigManager configManager)
|
AgilityConfig getConfig(ConfigManager configManager)
|
||||||
{
|
{
|
||||||
@@ -126,6 +132,7 @@ public class AgilityPlugin extends Plugin
|
|||||||
{
|
{
|
||||||
overlayManager.add(agilityOverlay);
|
overlayManager.add(agilityOverlay);
|
||||||
overlayManager.add(lapCounterOverlay);
|
overlayManager.add(lapCounterOverlay);
|
||||||
|
agilityLevel = client.getBoostedSkillLevel(Skill.AGILITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -136,6 +143,7 @@ public class AgilityPlugin extends Plugin
|
|||||||
marksOfGrace.clear();
|
marksOfGrace.clear();
|
||||||
obstacles.clear();
|
obstacles.clear();
|
||||||
session = null;
|
session = null;
|
||||||
|
agilityLevel = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@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
|
@Subscribe
|
||||||
public void onItemSpawned(ItemSpawned itemSpawned)
|
public void onItemSpawned(ItemSpawned itemSpawned)
|
||||||
{
|
{
|
||||||
@@ -366,11 +385,40 @@ public class AgilityPlugin extends Plugin
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Obstacles.COURSE_OBSTACLE_IDS.contains(newObject.getId()) ||
|
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_IDS.contains(newObject.getId())
|
||||||
&& Obstacles.TRAP_OBSTACLE_REGIONS.contains(newObject.getWorldLocation().getRegionID())))
|
&& 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;
|
package net.runelite.client.plugins.agility;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.ImmutableMultimap;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
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 static net.runelite.api.ObjectID.*;
|
||||||
|
import net.runelite.client.game.AgilityShortcut;
|
||||||
|
|
||||||
class Obstacles
|
class Obstacles
|
||||||
{
|
{
|
||||||
@@ -62,7 +78,7 @@ class Obstacles
|
|||||||
STEPPING_STONE_15412, TROPICAL_TREE_15414, MONKEYBARS_15417, SKULL_SLOPE_15483, ROPE_15487, TROPICAL_TREE_16062,
|
STEPPING_STONE_15412, TROPICAL_TREE_15414, MONKEYBARS_15417, SKULL_SLOPE_15483, ROPE_15487, TROPICAL_TREE_16062,
|
||||||
// Falador
|
// Falador
|
||||||
ROUGH_WALL_10833, TIGHTROPE_10834, HAND_HOLDS_10836, GAP_11161, GAP_11360, TIGHTROPE_11361,
|
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
|
// Wilderness
|
||||||
OBSTACLE_PIPE_23137, ROPESWING_23132, STEPPING_STONE_23556, LOG_BALANCE_23542, ROCKS_23640,
|
OBSTACLE_PIPE_23137, ROPESWING_23132, STEPPING_STONE_23556, LOG_BALANCE_23542, ROCKS_23640,
|
||||||
// Seers
|
// Seers
|
||||||
@@ -91,144 +107,7 @@ class Obstacles
|
|||||||
ZIP_LINE_11645, ZIP_LINE_11646
|
ZIP_LINE_11645, ZIP_LINE_11646
|
||||||
);
|
);
|
||||||
|
|
||||||
static final Set<Integer> SHORTCUT_OBSTACLE_IDS = ImmutableSet.of(
|
static final Multimap<Integer, AgilityShortcut> SHORTCUT_OBSTACLE_IDS;
|
||||||
// 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 Set<Integer> TRAP_OBSTACLE_IDS = ImmutableSet.of(
|
static final Set<Integer> TRAP_OBSTACLE_IDS = ImmutableSet.of(
|
||||||
// Agility pyramid
|
// Agility pyramid
|
||||||
@@ -236,4 +115,17 @@ class Obstacles
|
|||||||
);
|
);
|
||||||
|
|
||||||
static final List<Integer> TRAP_OBSTACLE_REGIONS = ImmutableList.of(12105, 13356);
|
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.config.ConfigManager;
|
||||||
import net.runelite.client.eventbus.Subscribe;
|
import net.runelite.client.eventbus.Subscribe;
|
||||||
import net.runelite.client.game.ItemManager;
|
import net.runelite.client.game.ItemManager;
|
||||||
|
import net.runelite.client.game.SpriteManager;
|
||||||
import net.runelite.client.game.chatbox.ChatboxPanelManager;
|
import net.runelite.client.game.chatbox.ChatboxPanelManager;
|
||||||
import net.runelite.client.input.KeyListener;
|
import net.runelite.client.input.KeyListener;
|
||||||
import net.runelite.client.input.KeyManager;
|
import net.runelite.client.input.KeyManager;
|
||||||
@@ -125,6 +126,9 @@ public class BankTagsPlugin extends Plugin implements MouseWheelListener, KeyLis
|
|||||||
@Inject
|
@Inject
|
||||||
private KeyManager keyManager;
|
private KeyManager keyManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private SpriteManager spriteManager;
|
||||||
|
|
||||||
private boolean shiftPressed = false;
|
private boolean shiftPressed = false;
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@@ -139,7 +143,7 @@ public class BankTagsPlugin extends Plugin implements MouseWheelListener, KeyLis
|
|||||||
keyManager.registerKeyListener(this);
|
keyManager.registerKeyListener(this);
|
||||||
mouseManager.registerMouseWheelListener(this);
|
mouseManager.registerMouseWheelListener(this);
|
||||||
clientThread.invokeLater(tabInterface::init);
|
clientThread.invokeLater(tabInterface::init);
|
||||||
client.getSpriteOverrides().putAll(TabSprites.toMap(client));
|
spriteManager.addSpriteOverrides(TabSprites.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -148,11 +152,7 @@ public class BankTagsPlugin extends Plugin implements MouseWheelListener, KeyLis
|
|||||||
keyManager.unregisterKeyListener(this);
|
keyManager.unregisterKeyListener(this);
|
||||||
mouseManager.unregisterMouseWheelListener(this);
|
mouseManager.unregisterMouseWheelListener(this);
|
||||||
clientThread.invokeLater(tabInterface::destroy);
|
clientThread.invokeLater(tabInterface::destroy);
|
||||||
|
spriteManager.removeSpriteOverrides(TabSprites.values());
|
||||||
for (TabSprites value : TabSprites.values())
|
|
||||||
{
|
|
||||||
client.getSpriteOverrides().remove(value.getSpriteId());
|
|
||||||
}
|
|
||||||
|
|
||||||
shiftPressed = false;
|
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)
|
private int getItemId(int itemId, boolean variation)
|
||||||
{
|
{
|
||||||
itemId = Math.abs(itemId);
|
itemId = Math.abs(itemId);
|
||||||
|
|||||||
@@ -39,5 +39,6 @@ class MenuIndexes
|
|||||||
static final int CHANGE_ICON = 3;
|
static final int CHANGE_ICON = 3;
|
||||||
static final int DELETE_TAB = 4;
|
static final int DELETE_TAB = 4;
|
||||||
static final int EXPORT_TAB = 5;
|
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.VarClientInt;
|
||||||
import net.runelite.api.VarClientStr;
|
import net.runelite.api.VarClientStr;
|
||||||
import net.runelite.api.Varbits;
|
import net.runelite.api.Varbits;
|
||||||
import net.runelite.api.widgets.WidgetType;
|
|
||||||
import net.runelite.api.events.MenuEntryAdded;
|
import net.runelite.api.events.MenuEntryAdded;
|
||||||
import net.runelite.api.events.MenuOptionClicked;
|
import net.runelite.api.events.MenuOptionClicked;
|
||||||
import net.runelite.api.vars.InputType;
|
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.Widget;
|
||||||
import net.runelite.api.widgets.WidgetConfig;
|
import net.runelite.api.widgets.WidgetConfig;
|
||||||
import net.runelite.api.widgets.WidgetInfo;
|
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.Notifier;
|
||||||
import net.runelite.client.callback.ClientThread;
|
import net.runelite.client.callback.ClientThread;
|
||||||
import net.runelite.client.config.ConfigManager;
|
|
||||||
import net.runelite.client.game.ItemManager;
|
import net.runelite.client.game.ItemManager;
|
||||||
import net.runelite.client.game.chatbox.ChatboxPanelManager;
|
import net.runelite.client.game.chatbox.ChatboxPanelManager;
|
||||||
import net.runelite.client.plugins.banktags.BankTagsConfig;
|
import net.runelite.client.plugins.banktags.BankTagsConfig;
|
||||||
import net.runelite.client.plugins.banktags.BankTagsPlugin;
|
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.TAG_SEARCH;
|
||||||
import static net.runelite.client.plugins.banktags.BankTagsPlugin.VAR_TAG_SUFFIX;
|
import static net.runelite.client.plugins.banktags.BankTagsPlugin.VAR_TAG_SUFFIX;
|
||||||
import net.runelite.client.plugins.banktags.TagManager;
|
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 EXPORT_TAB = "Export tag tab";
|
||||||
private static final String IMPORT_TAB = "Import tag tab";
|
private static final String IMPORT_TAB = "Import tag tab";
|
||||||
private static final String VIEW_TAB = "View 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 CHANGE_ICON = "Change icon";
|
||||||
private static final String REMOVE_TAG = "Remove-tag";
|
private static final String REMOVE_TAG = "Remove-tag";
|
||||||
private static final String TAG_GEAR = "Tag-equipment";
|
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 BUTTON_HEIGHT = 20;
|
||||||
private static final int MARGIN = 1;
|
private static final int MARGIN = 1;
|
||||||
private static final int SCROLL_TICK = 500;
|
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 Client client;
|
||||||
private final ClientThread clientThread;
|
private final ClientThread clientThread;
|
||||||
private final ItemManager itemManager;
|
private final ItemManager itemManager;
|
||||||
private final ConfigManager configManager;
|
|
||||||
private final TagManager tagManager;
|
private final TagManager tagManager;
|
||||||
private final TabManager tabManager;
|
private final TabManager tabManager;
|
||||||
private final ChatboxPanelManager chatboxPanelManager;
|
private final ChatboxPanelManager chatboxPanelManager;
|
||||||
@@ -148,7 +148,6 @@ public class TabInterface
|
|||||||
final Client client,
|
final Client client,
|
||||||
final ClientThread clientThread,
|
final ClientThread clientThread,
|
||||||
final ItemManager itemManager,
|
final ItemManager itemManager,
|
||||||
final ConfigManager configManager,
|
|
||||||
final TagManager tagManager,
|
final TagManager tagManager,
|
||||||
final TabManager tabManager,
|
final TabManager tabManager,
|
||||||
final ChatboxPanelManager chatboxPanelManager,
|
final ChatboxPanelManager chatboxPanelManager,
|
||||||
@@ -159,7 +158,6 @@ public class TabInterface
|
|||||||
this.client = client;
|
this.client = client;
|
||||||
this.clientThread = clientThread;
|
this.clientThread = clientThread;
|
||||||
this.itemManager = itemManager;
|
this.itemManager = itemManager;
|
||||||
this.configManager = configManager;
|
|
||||||
this.tagManager = tagManager;
|
this.tagManager = tagManager;
|
||||||
this.tabManager = tabManager;
|
this.tabManager = tabManager;
|
||||||
this.chatboxPanelManager = chatboxPanelManager;
|
this.chatboxPanelManager = chatboxPanelManager;
|
||||||
@@ -211,7 +209,7 @@ public class TabInterface
|
|||||||
|
|
||||||
if (config.rememberTab() && !Strings.isNullOrEmpty(config.tab()))
|
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);
|
tagManager.addTag(item, activeTab.getTag(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
openTag(TAG_SEARCH + activeTab.getTag());
|
openTag(activeTab.getTag());
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -292,7 +290,7 @@ public class TabInterface
|
|||||||
final Iterator<String> dataIter = Text.fromCSV(dataString).iterator();
|
final Iterator<String> dataIter = Text.fromCSV(dataString).iterator();
|
||||||
final String name = dataIter.next();
|
final String name = dataIter.next();
|
||||||
final String icon = dataIter.next();
|
final String icon = dataIter.next();
|
||||||
configManager.setConfiguration(CONFIG_GROUP, ICON_SEARCH + name, icon);
|
tabManager.setIcon(name, icon);
|
||||||
|
|
||||||
while (dataIter.hasNext())
|
while (dataIter.hasNext())
|
||||||
{
|
{
|
||||||
@@ -306,7 +304,7 @@ public class TabInterface
|
|||||||
|
|
||||||
if (activeTab != null && name.equals(activeTab.getTag()))
|
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!");
|
notifier.notify("Tag tab " + name + " has been imported from your clipboard!");
|
||||||
@@ -336,7 +334,7 @@ public class TabInterface
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
openTag(TAG_SEARCH + Text.removeTags(clicked.getName()));
|
openTag(Text.removeTags(clicked.getName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
client.playSoundEffect(SoundEffectID.UI_BOOP);
|
client.playSoundEffect(SoundEffectID.UI_BOOP);
|
||||||
@@ -373,6 +371,10 @@ public class TabInterface
|
|||||||
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(stringSelection, null);
|
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(stringSelection, null);
|
||||||
notifier.notify("Tag tab " + tagTab.getTag() + " has been copied to your clipboard!");
|
notifier.notify("Tag tab " + tagTab.getTag() + " has been copied to your clipboard!");
|
||||||
break;
|
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());
|
int itemId = itemManager.canonicalize(item.getId());
|
||||||
iconToSet.setIconItemId(itemId);
|
iconToSet.setIconItemId(itemId);
|
||||||
iconToSet.getIcon().setItemId(itemId);
|
iconToSet.getIcon().setItemId(itemId);
|
||||||
configManager.setConfiguration(CONFIG_GROUP, ICON_SEARCH + iconToSet.getTag(), itemId + "");
|
tabManager.setIcon(iconToSet.getTag(), itemId + "");
|
||||||
event.consume();
|
event.consume();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -597,7 +599,7 @@ public class TabInterface
|
|||||||
{
|
{
|
||||||
if (activeTab != null && tags.contains(activeTab.getTag()))
|
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(2, CHANGE_ICON);
|
||||||
btn.setAction(3, REMOVE_TAB);
|
btn.setAction(3, REMOVE_TAB);
|
||||||
btn.setAction(4, EXPORT_TAB);
|
btn.setAction(4, EXPORT_TAB);
|
||||||
|
btn.setAction(5, RENAME_TAB);
|
||||||
btn.setOnOpListener((JavaScriptCallback) this::handleTagTab);
|
btn.setOnOpListener((JavaScriptCallback) this::handleTagTab);
|
||||||
tagTab.setBackground(btn);
|
tagTab.setBackground(btn);
|
||||||
}
|
}
|
||||||
@@ -712,13 +715,66 @@ public class TabInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
tabManager.remove(tag);
|
tabManager.remove(tag);
|
||||||
configManager.unsetConfiguration(CONFIG_GROUP, ICON_SEARCH + tag);
|
|
||||||
tabManager.save();
|
tabManager.save();
|
||||||
|
|
||||||
updateBounds();
|
updateBounds();
|
||||||
scrollTab(0);
|
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)
|
private void scrollTick(int direction)
|
||||||
{
|
{
|
||||||
// This ensures that dragging on scroll buttons do not scrolls too fast
|
// This ensures that dragging on scroll buttons do not scrolls too fast
|
||||||
@@ -805,17 +861,18 @@ public class TabInterface
|
|||||||
|
|
||||||
if (incinerator != null && !incinerator.isHidden())
|
if (incinerator != null && !incinerator.isHidden())
|
||||||
{
|
{
|
||||||
// This is the required way to move incinerator, don't change it!
|
incinerator.setOriginalHeight(INCINERATOR_HEIGHT);
|
||||||
incinerator.setOriginalHeight(39);
|
incinerator.setOriginalWidth(INCINERATOR_WIDTH);
|
||||||
incinerator.setOriginalWidth(48);
|
incinerator.setOriginalY(INCINERATOR_HEIGHT);
|
||||||
incinerator.setRelativeY(itemContainer.getHeight());
|
|
||||||
incinerator.revalidate();
|
|
||||||
|
|
||||||
Widget child = incinerator.getDynamicChildren()[0];
|
Widget child = incinerator.getDynamicChildren()[0];
|
||||||
child.setHeight(39);
|
child.setOriginalHeight(INCINERATOR_HEIGHT);
|
||||||
child.setWidth(48);
|
child.setOriginalWidth(INCINERATOR_WIDTH);
|
||||||
|
child.setWidthMode(WidgetSizeMode.ABSOLUTE);
|
||||||
|
child.setHeightMode(WidgetSizeMode.ABSOLUTE);
|
||||||
child.setType(WidgetType.GRAPHIC);
|
child.setType(WidgetType.GRAPHIC);
|
||||||
child.setSpriteId(TabSprites.INCINERATOR.getSpriteId());
|
child.setSpriteId(TabSprites.INCINERATOR.getSpriteId());
|
||||||
|
incinerator.revalidate();
|
||||||
|
|
||||||
bounds.setSize(TAB_WIDTH + MARGIN * 2, height - incinerator.getHeight());
|
bounds.setSize(TAB_WIDTH + MARGIN * 2, height - incinerator.getHeight());
|
||||||
}
|
}
|
||||||
@@ -900,7 +957,6 @@ public class TabInterface
|
|||||||
private void updateWidget(Widget t, int y)
|
private void updateWidget(Widget t, int y)
|
||||||
{
|
{
|
||||||
t.setOriginalY(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.setHidden(y < (bounds.y + BUTTON_HEIGHT + MARGIN) || y > (bounds.y + bounds.height - TAB_HEIGHT - MARGIN - BUTTON_HEIGHT));
|
||||||
t.revalidate();
|
t.revalidate();
|
||||||
}
|
}
|
||||||
@@ -913,10 +969,10 @@ public class TabInterface
|
|||||||
return itemManager.getItemComposition(item.getId());
|
return itemManager.getItemComposition(item.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void openTag(String tag)
|
private void openTag(final String tag)
|
||||||
{
|
{
|
||||||
bankSearch.search(InputType.SEARCH, tag, true);
|
bankSearch.search(InputType.SEARCH, TAG_SEARCH + tag, true);
|
||||||
activateTab(tabManager.find(tag.substring(TAG_SEARCH.length())));
|
activateTab(tabManager.find(tag));
|
||||||
|
|
||||||
// When tab is selected with search window open, the search window closes but the search button
|
// When tab is selected with search window open, the search window closes but the search button
|
||||||
// stays highlighted, this solves that issue
|
// stays highlighted, this solves that issue
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ class TabManager
|
|||||||
{
|
{
|
||||||
tagTab.setHidden(true);
|
tagTab.setHidden(true);
|
||||||
tabs.remove(tagTab);
|
tabs.remove(tagTab);
|
||||||
|
removeIcon(tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,6 +125,16 @@ class TabManager
|
|||||||
configManager.setConfiguration(CONFIG_GROUP, TAG_TABS_CONFIG, tags);
|
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()
|
int size()
|
||||||
{
|
{
|
||||||
return tabs.size();
|
return tabs.size();
|
||||||
|
|||||||
@@ -25,17 +25,12 @@
|
|||||||
*/
|
*/
|
||||||
package net.runelite.client.plugins.banktags.tabs;
|
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.Getter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.RequiredArgsConstructor;
|
||||||
import net.runelite.api.Client;
|
import net.runelite.client.game.SpriteOverride;
|
||||||
import net.runelite.api.SpritePixels;
|
|
||||||
import net.runelite.client.util.ImageUtil;
|
|
||||||
|
|
||||||
@Slf4j
|
@RequiredArgsConstructor
|
||||||
public enum TabSprites
|
public enum TabSprites implements SpriteOverride
|
||||||
{
|
{
|
||||||
INCINERATOR(-200, "incinerator.png"),
|
INCINERATOR(-200, "incinerator.png"),
|
||||||
TAB_BACKGROUND(-201, "tag-tab.png"),
|
TAB_BACKGROUND(-201, "tag-tab.png"),
|
||||||
@@ -46,23 +41,7 @@ public enum TabSprites
|
|||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final int spriteId;
|
private final int spriteId;
|
||||||
private final BufferedImage image;
|
|
||||||
|
|
||||||
TabSprites(final int spriteId, final String imageName)
|
@Getter
|
||||||
{
|
private final String fileName;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ import net.runelite.api.widgets.Widget;
|
|||||||
@EqualsAndHashCode(of = "tag")
|
@EqualsAndHashCode(of = "tag")
|
||||||
class TagTab
|
class TagTab
|
||||||
{
|
{
|
||||||
private final String tag;
|
private String tag;
|
||||||
private int iconItemId;
|
private int iconItemId;
|
||||||
private Widget background;
|
private Widget background;
|
||||||
private Widget icon;
|
private Widget icon;
|
||||||
|
|||||||
@@ -26,15 +26,15 @@ package net.runelite.client.plugins.cannon;
|
|||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.image.BufferedImage;
|
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;
|
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;
|
this.plugin = plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,7 +75,8 @@ public class CerberusPlugin extends Plugin
|
|||||||
@Subscribe
|
@Subscribe
|
||||||
public void onGameStateChanged(GameStateChanged event)
|
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();
|
ghosts.clear();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -299,7 +299,7 @@ public class ChatCommandsPlugin extends Plugin
|
|||||||
Widget boss = bossChildren[i];
|
Widget boss = bossChildren[i];
|
||||||
Widget kill = killsChildren[i];
|
Widget kill = killsChildren[i];
|
||||||
|
|
||||||
String bossName = boss.getText();
|
String bossName = boss.getText().replace(":", "");
|
||||||
int kc = Integer.parseInt(kill.getText().replace(",", ""));
|
int kc = Integer.parseInt(kill.getText().replace(",", ""));
|
||||||
if (kc != getKc(bossName))
|
if (kc != getKc(bossName))
|
||||||
{
|
{
|
||||||
@@ -1089,6 +1089,7 @@ public class ChatCommandsPlugin extends Plugin
|
|||||||
case "barrows":
|
case "barrows":
|
||||||
return "Barrows Chests";
|
return "Barrows Chests";
|
||||||
|
|
||||||
|
// cox
|
||||||
case "cox":
|
case "cox":
|
||||||
case "xeric":
|
case "xeric":
|
||||||
case "chambers":
|
case "chambers":
|
||||||
@@ -1096,6 +1097,15 @@ public class ChatCommandsPlugin extends Plugin
|
|||||||
case "raids":
|
case "raids":
|
||||||
return "Chambers of Xeric";
|
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 "tob":
|
||||||
case "theatre":
|
case "theatre":
|
||||||
case "verzik":
|
case "verzik":
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
* Copyright (c) 2018, TheStonedTurtle <https://github.com/TheStonedTurtle>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* 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
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* 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 net.runelite.client.config.Config;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import net.runelite.client.config.ConfigGroup;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
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<>();
|
@ConfigItem(
|
||||||
|
keyName = "retainChatHistory",
|
||||||
public static void changeSessionUID(WSService service, UUID uuid)
|
name = "Retain Chat History",
|
||||||
|
description = "Retains chat history when logging in/out or world hopping",
|
||||||
|
position = 0
|
||||||
|
)
|
||||||
|
default boolean retainChatHistory()
|
||||||
{
|
{
|
||||||
synchronized (service)
|
return true;
|
||||||
{
|
|
||||||
remove(service);
|
|
||||||
service.setUuid(uuid);
|
|
||||||
sessions.put(uuid, service);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
return true;
|
||||||
{
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -25,47 +25,74 @@
|
|||||||
package net.runelite.client.plugins.chathistory;
|
package net.runelite.client.plugins.chathistory;
|
||||||
|
|
||||||
import com.google.common.collect.EvictingQueue;
|
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.Queue;
|
||||||
import java.util.Set;
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import net.runelite.api.ChatMessageType;
|
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.ChatMessage;
|
||||||
import net.runelite.api.events.MenuOptionClicked;
|
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.ChatMessageManager;
|
||||||
import net.runelite.client.chat.QueuedMessage;
|
import net.runelite.client.chat.QueuedMessage;
|
||||||
|
import net.runelite.client.config.ConfigManager;
|
||||||
import net.runelite.client.eventbus.Subscribe;
|
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.Plugin;
|
||||||
import net.runelite.client.plugins.PluginDescriptor;
|
import net.runelite.client.plugins.PluginDescriptor;
|
||||||
|
import net.runelite.client.util.Text;
|
||||||
|
|
||||||
@PluginDescriptor(
|
@PluginDescriptor(
|
||||||
name = "Chat History",
|
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 WELCOME_MESSAGE = "Welcome to Old School RuneScape.";
|
||||||
private static final String CLEAR_HISTORY = "Clear history";
|
private static final String CLEAR_HISTORY = "Clear history";
|
||||||
private static final String CLEAR_PRIVATE = "<col=ffff00>Private:";
|
private static final String CLEAR_PRIVATE = "<col=ffff00>Private:";
|
||||||
private static final Set<ChatMessageType> ALLOWED_HISTORY = Sets.newHashSet(
|
private static final int CYCLE_HOTKEY = KeyEvent.VK_TAB;
|
||||||
ChatMessageType.PUBLIC,
|
|
||||||
ChatMessageType.PUBLIC_MOD,
|
|
||||||
ChatMessageType.CLANCHAT,
|
|
||||||
ChatMessageType.PRIVATE_MESSAGE_RECEIVED,
|
|
||||||
ChatMessageType.PRIVATE_MESSAGE_SENT,
|
|
||||||
ChatMessageType.PRIVATE_MESSAGE_RECEIVED_MOD,
|
|
||||||
ChatMessageType.GAME
|
|
||||||
);
|
|
||||||
|
|
||||||
private Queue<QueuedMessage> messageQueue;
|
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
|
@Inject
|
||||||
private ChatMessageManager chatMessageManager;
|
private ChatMessageManager chatMessageManager;
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
ChatHistoryConfig getConfig(ConfigManager configManager)
|
||||||
|
{
|
||||||
|
return configManager.getConfig(ChatHistoryConfig.class);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void startUp()
|
protected void startUp()
|
||||||
{
|
{
|
||||||
messageQueue = EvictingQueue.create(100);
|
messageQueue = EvictingQueue.create(100);
|
||||||
|
friends = new ArrayDeque<>(5);
|
||||||
|
keyManager.registerKeyListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -73,6 +100,9 @@ public class ChatHistoryPlugin extends Plugin
|
|||||||
{
|
{
|
||||||
messageQueue.clear();
|
messageQueue.clear();
|
||||||
messageQueue = null;
|
messageQueue = null;
|
||||||
|
friends.clear();
|
||||||
|
friends = null;
|
||||||
|
keyManager.unregisterKeyListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
@@ -82,6 +112,11 @@ public class ChatHistoryPlugin extends Plugin
|
|||||||
// of information that chat history was reset
|
// of information that chat history was reset
|
||||||
if (chatMessage.getMessage().equals(WELCOME_MESSAGE))
|
if (chatMessage.getMessage().equals(WELCOME_MESSAGE))
|
||||||
{
|
{
|
||||||
|
if (!config.retainChatHistory())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QueuedMessage queuedMessage;
|
QueuedMessage queuedMessage;
|
||||||
|
|
||||||
while ((queuedMessage = messageQueue.poll()) != null)
|
while ((queuedMessage = messageQueue.poll()) != null)
|
||||||
@@ -92,21 +127,33 @@ public class ChatHistoryPlugin extends Plugin
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ALLOWED_HISTORY.contains(chatMessage.getType()))
|
switch (chatMessage.getType())
|
||||||
{
|
{
|
||||||
final QueuedMessage queuedMessage = QueuedMessage.builder()
|
case PRIVATE_MESSAGE_SENT:
|
||||||
.type(chatMessage.getType())
|
case PRIVATE_MESSAGE_RECEIVED:
|
||||||
.name(chatMessage.getName())
|
case PRIVATE_MESSAGE_RECEIVED_MOD:
|
||||||
.sender(chatMessage.getSender())
|
final String name = Text.removeTags(chatMessage.getName());
|
||||||
.value(nbsp(chatMessage.getMessage()))
|
// Remove to ensure uniqueness & its place in history
|
||||||
.runeLiteFormattedMessage(nbsp(chatMessage.getMessageNode().getRuneLiteFormatMessage()))
|
friends.remove(name);
|
||||||
.timestamp(chatMessage.getTimestamp())
|
friends.add(name);
|
||||||
.build();
|
// 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))
|
if (!messageQueue.contains(queuedMessage))
|
||||||
{
|
{
|
||||||
messageQueue.offer(queuedMessage);
|
messageQueue.offer(queuedMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,4 +190,64 @@ public class ChatHistoryPlugin extends Plugin
|
|||||||
|
|
||||||
return null;
|
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 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 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("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("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))),
|
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 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 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)),
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
panelComponent.setPreferredSize(new Dimension(145, 0));
|
|
||||||
panelComponent.getChildren().clear();
|
panelComponent.getChildren().clear();
|
||||||
|
|
||||||
if (isCooking() || Duration.between(session.getLastCookingAction(), Instant.now()).getSeconds() < COOK_TIMEOUT)
|
if (isCooking() || Duration.between(session.getLastCookingAction(), Instant.now()).getSeconds() < COOK_TIMEOUT)
|
||||||
|
|||||||
@@ -347,6 +347,12 @@ class DevToolsOverlay extends Overlay
|
|||||||
{
|
{
|
||||||
graphics.drawPolygon(p);
|
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<>("ScrollHeight", Widget::getScrollHeight, Widget::setScrollHeight, Integer.class));
|
||||||
out.add(new WidgetField<>("DragDeadZone", Widget::getDragDeadZone, Widget::setDragDeadZone, 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<>("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;
|
return out;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -130,6 +130,7 @@ public class DiscordPlugin extends Plugin
|
|||||||
|
|
||||||
clientToolbar.addNavigation(discordButton);
|
clientToolbar.addNavigation(discordButton);
|
||||||
checkForGameStateUpdate();
|
checkForGameStateUpdate();
|
||||||
|
checkForAreaUpdate();
|
||||||
|
|
||||||
if (discordService.getCurrentUser() != null)
|
if (discordService.getCurrentUser() != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import java.util.Optional;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import net.runelite.client.RuneLiteProperties;
|
||||||
import net.runelite.client.discord.DiscordPresence;
|
import net.runelite.client.discord.DiscordPresence;
|
||||||
import net.runelite.client.discord.DiscordService;
|
import net.runelite.client.discord.DiscordService;
|
||||||
import net.runelite.client.ws.PartyService;
|
import net.runelite.client.ws.PartyService;
|
||||||
@@ -57,14 +58,16 @@ class DiscordState
|
|||||||
private final DiscordService discordService;
|
private final DiscordService discordService;
|
||||||
private final DiscordConfig config;
|
private final DiscordConfig config;
|
||||||
private PartyService party;
|
private PartyService party;
|
||||||
|
private final RuneLiteProperties properties;
|
||||||
private DiscordPresence lastPresence;
|
private DiscordPresence lastPresence;
|
||||||
|
|
||||||
@Inject
|
@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.discordService = discordService;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.party = party;
|
this.party = party;
|
||||||
|
this.properties = properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -90,6 +93,7 @@ class DiscordState
|
|||||||
final DiscordPresence.DiscordPresenceBuilder presenceBuilder = DiscordPresence.builder()
|
final DiscordPresence.DiscordPresenceBuilder presenceBuilder = DiscordPresence.builder()
|
||||||
.state(lastPresence.getState())
|
.state(lastPresence.getState())
|
||||||
.details(lastPresence.getDetails())
|
.details(lastPresence.getDetails())
|
||||||
|
.largeImageText(lastPresence.getLargeImageText())
|
||||||
.startTimestamp(lastPresence.getStartTimestamp())
|
.startTimestamp(lastPresence.getStartTimestamp())
|
||||||
.smallImageKey(lastPresence.getSmallImageKey())
|
.smallImageKey(lastPresence.getSmallImageKey())
|
||||||
.partyMax(lastPresence.getPartyMax())
|
.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()
|
final DiscordPresence.DiscordPresenceBuilder presenceBuilder = DiscordPresence.builder()
|
||||||
.state(MoreObjects.firstNonNull(state, ""))
|
.state(MoreObjects.firstNonNull(state, ""))
|
||||||
.details(MoreObjects.firstNonNull(details, ""))
|
.details(MoreObjects.firstNonNull(details, ""))
|
||||||
|
.largeImageText(properties.getTitle() + " v" + versionShortHand)
|
||||||
.startTimestamp(event.getStart())
|
.startTimestamp(event.getStart())
|
||||||
.smallImageKey(MoreObjects.firstNonNull(imageKey, "default"))
|
.smallImageKey(imageKey)
|
||||||
.partyMax(PARTY_MAX)
|
.partyMax(PARTY_MAX)
|
||||||
.partySize(party.getMembers().size());
|
.partySize(party.getMembers().size());
|
||||||
|
|
||||||
|
|||||||
@@ -24,10 +24,12 @@
|
|||||||
*/
|
*/
|
||||||
package net.runelite.client.plugins.discord;
|
package net.runelite.client.plugins.discord;
|
||||||
|
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
import net.runelite.http.api.ws.messages.party.PartyMemberMessage;
|
import net.runelite.http.api.ws.messages.party.PartyMemberMessage;
|
||||||
|
|
||||||
@Value
|
@Value
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
class DiscordUserInfo extends PartyMemberMessage
|
class DiscordUserInfo extends PartyMemberMessage
|
||||||
{
|
{
|
||||||
private final String userId;
|
private final String userId;
|
||||||
|
|||||||
@@ -147,7 +147,8 @@ public class FishingPlugin extends Plugin
|
|||||||
@Subscribe
|
@Subscribe
|
||||||
public void onGameStateChanged(GameStateChanged gameStateChanged)
|
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();
|
fishingSpots.clear();
|
||||||
minnowSpots.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.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())
|
if (client.isStretchedEnabled())
|
||||||
{
|
{
|
||||||
Dimension dim = client.getStretchedDimensions();
|
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) 2017, Robbie <https://github.com/rbbi>
|
||||||
* Copyright (c) 2018, SomeoneWithAnInternetConnection
|
* Copyright (c) 2018, SomeoneWithAnInternetConnection
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
@@ -46,6 +46,7 @@ import net.runelite.api.ChatMessageType;
|
|||||||
import net.runelite.api.Client;
|
import net.runelite.api.Client;
|
||||||
import net.runelite.api.GameState;
|
import net.runelite.api.GameState;
|
||||||
import net.runelite.api.GrandExchangeOffer;
|
import net.runelite.api.GrandExchangeOffer;
|
||||||
|
import net.runelite.api.GrandExchangeOfferState;
|
||||||
import net.runelite.api.ItemComposition;
|
import net.runelite.api.ItemComposition;
|
||||||
import net.runelite.api.MenuAction;
|
import net.runelite.api.MenuAction;
|
||||||
import net.runelite.api.MenuEntry;
|
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.GameTick;
|
||||||
import net.runelite.api.events.GrandExchangeOfferChanged;
|
import net.runelite.api.events.GrandExchangeOfferChanged;
|
||||||
import net.runelite.api.events.MenuEntryAdded;
|
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.events.WidgetLoaded;
|
||||||
import net.runelite.api.widgets.Widget;
|
import net.runelite.api.widgets.Widget;
|
||||||
import net.runelite.api.widgets.WidgetID;
|
import net.runelite.api.widgets.WidgetID;
|
||||||
import net.runelite.api.widgets.WidgetInfo;
|
import net.runelite.api.widgets.WidgetInfo;
|
||||||
import net.runelite.client.Notifier;
|
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.config.ConfigManager;
|
||||||
import net.runelite.client.eventbus.Subscribe;
|
import net.runelite.client.eventbus.Subscribe;
|
||||||
import net.runelite.client.game.ItemManager;
|
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.ImageUtil;
|
||||||
import net.runelite.client.util.StackFormatter;
|
import net.runelite.client.util.StackFormatter;
|
||||||
import net.runelite.client.util.Text;
|
import net.runelite.client.util.Text;
|
||||||
import net.runelite.http.api.osbuddy.GrandExchangeClient;
|
import net.runelite.http.api.ge.GrandExchangeClient;
|
||||||
import net.runelite.http.api.osbuddy.GrandExchangeResult;
|
import net.runelite.http.api.ge.GrandExchangeTrade;
|
||||||
|
import net.runelite.http.api.osbuddy.OSBGrandExchangeClient;
|
||||||
|
import net.runelite.http.api.osbuddy.OSBGrandExchangeResult;
|
||||||
|
|
||||||
@PluginDescriptor(
|
@PluginDescriptor(
|
||||||
name = "Grand Exchange",
|
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_CONTAINER_ITEM = 21;
|
||||||
private static final int OFFER_DEFAULT_ITEM_ID = 6512;
|
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 OSB_GE_TEXT = "<br>OSBuddy Actively traded price: ";
|
||||||
|
|
||||||
private static final String BUY_LIMIT_GE_TEXT = "<br>Buy limit: ";
|
private static final String BUY_LIMIT_GE_TEXT = "<br>Buy limit: ";
|
||||||
@@ -134,10 +141,38 @@ public class GrandExchangePlugin extends Plugin
|
|||||||
@Inject
|
@Inject
|
||||||
private ScheduledExecutorService executorService;
|
private ScheduledExecutorService executorService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private SessionManager sessionManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private ConfigManager configManager;
|
||||||
|
|
||||||
private Widget grandExchangeText;
|
private Widget grandExchangeText;
|
||||||
private Widget grandExchangeItem;
|
private Widget grandExchangeItem;
|
||||||
private Map<Integer, Integer> itemGELimits;
|
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
|
@Provides
|
||||||
GrandExchangeConfig provideConfig(ConfigManager configManager)
|
GrandExchangeConfig provideConfig(ConfigManager configManager)
|
||||||
{
|
{
|
||||||
@@ -167,6 +202,12 @@ public class GrandExchangePlugin extends Plugin
|
|||||||
mouseManager.registerMouseListener(inputListener);
|
mouseManager.registerMouseListener(inputListener);
|
||||||
keyManager.registerKeyListener(inputListener);
|
keyManager.registerKeyListener(inputListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AccountSession accountSession = sessionManager.getAccountSession();
|
||||||
|
if (accountSession != null)
|
||||||
|
{
|
||||||
|
grandExchangeClient = new GrandExchangeClient(accountSession.getUuid());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -178,6 +219,27 @@ public class GrandExchangePlugin extends Plugin
|
|||||||
grandExchangeText = null;
|
grandExchangeText = null;
|
||||||
grandExchangeItem = null;
|
grandExchangeItem = null;
|
||||||
itemGELimits = 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
|
@Subscribe
|
||||||
@@ -204,11 +266,79 @@ public class GrandExchangePlugin extends Plugin
|
|||||||
@Subscribe
|
@Subscribe
|
||||||
public void onGrandExchangeOfferChanged(GrandExchangeOfferChanged offerEvent)
|
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());
|
ItemComposition offerItem = itemManager.getItemComposition(offer.getItemId());
|
||||||
boolean shouldStack = offerItem.isStackable() || offer.getTotalQuantity() > 1;
|
boolean shouldStack = offerItem.isStackable() || offer.getTotalQuantity() > 1;
|
||||||
BufferedImage itemImage = itemManager.getImage(offer.getItemId(), offer.getTotalQuantity(), shouldStack);
|
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
|
@Subscribe
|
||||||
@@ -346,7 +476,7 @@ public class GrandExchangePlugin extends Plugin
|
|||||||
|
|
||||||
try
|
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());
|
final String text = geText.getText() + OSB_GE_TEXT + StackFormatter.formatNumber(result.getOverall_average());
|
||||||
geText.setText(text);
|
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