diff --git a/cache/pom.xml b/cache/pom.xml
index 7b5dd600556..b33784fcadb 100644
--- a/cache/pom.xml
+++ b/cache/pom.xml
@@ -29,7 +29,7 @@
net.runelite
runelite-parent
- 1.12.3
+ 1.12.4
cache
diff --git a/pom.xml b/pom.xml
index 503406ee2b2..ab0687f8c46 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,7 +28,7 @@
net.runelite
runelite-parent
- 1.12.3
+ 1.12.4
pom
RuneLite
diff --git a/runelite-api/pom.xml b/runelite-api/pom.xml
index aee2ec6043d..53c023a5944 100644
--- a/runelite-api/pom.xml
+++ b/runelite-api/pom.xml
@@ -29,7 +29,7 @@
net.runelite
runelite-parent
- 1.12.3
+ 1.12.4
runelite-api
diff --git a/runelite-client/pom.xml b/runelite-client/pom.xml
index 19489f10b0e..a89f0fe91eb 100644
--- a/runelite-client/pom.xml
+++ b/runelite-client/pom.xml
@@ -29,7 +29,7 @@
net.runelite
runelite-parent
- 1.12.3
+ 1.12.4
client
@@ -41,7 +41,7 @@
nogit
false
false
- 2.0.40
+ 2.0.41
nogit
diff --git a/runelite-client/src/main/java/net/runelite/client/callback/ClientThread.java b/runelite-client/src/main/java/net/runelite/client/callback/ClientThread.java
index 5ff96890ef2..4fbc990384c 100644
--- a/runelite-client/src/main/java/net/runelite/client/callback/ClientThread.java
+++ b/runelite-client/src/main/java/net/runelite/client/callback/ClientThread.java
@@ -35,6 +35,7 @@
import java.util.Optional;
import java.util.concurrent.*;
import java.util.function.BooleanSupplier;
+import java.util.function.Supplier;
@Singleton
@Slf4j
@@ -122,6 +123,40 @@ public void invoke(BooleanSupplier r)
invokeLater(r);
}
+ public T invoke(Supplier supplier) {
+ if (client.isClientThread()) {
+ return supplier.get();
+ }
+
+ CompletableFuture f = new CompletableFuture<>();
+ invoke(() -> {
+ try {
+ f.complete(supplier.get());
+ } catch (Throwable t) {
+ f.completeExceptionally(t);
+ }
+ });
+
+ try {
+ return f.get(10, TimeUnit.SECONDS); // configurable timeout
+ } catch (InterruptedException ie) {
+ Thread.currentThread().interrupt();
+ throw new RuntimeException("Interrupted waiting for client thread", ie);
+ } catch (TimeoutException te) {
+ throw new RuntimeException("Timed out waiting for client thread", te);
+ } catch (ExecutionException ee) {
+ // unwrap original cause
+ Throwable cause = ee.getCause();
+ if (cause instanceof RuntimeException) {
+ throw (RuntimeException) cause;
+ }
+ if (cause instanceof Error) {
+ throw (Error) cause;
+ }
+ throw new RuntimeException(cause);
+ }
+ }
+
/**
* Will run r on the game thread after this method returns
* If r returns false, r will be ran again, at a later point
diff --git a/runelite-client/src/main/java/net/runelite/client/config/ConfigProfile.java b/runelite-client/src/main/java/net/runelite/client/config/ConfigProfile.java
index f4e7058bff3..d6444535d56 100644
--- a/runelite-client/src/main/java/net/runelite/client/config/ConfigProfile.java
+++ b/runelite-client/src/main/java/net/runelite/client/config/ConfigProfile.java
@@ -36,14 +36,14 @@ public class ConfigProfile
@Getter
private final long id;
@Getter
- @Setter(AccessLevel.PACKAGE)
- private String name;
+ @Setter
+ public String name;
@Getter
- @Setter(AccessLevel.PACKAGE)
- private String password;
+ @Setter
+ public String password;
@Getter
- @Setter(AccessLevel.PACKAGE)
- private String bankPin;
+ @Setter
+ public String bankPin;
@Getter
@Setter
private long memberExpireDaysTimeStemp;
@@ -51,10 +51,10 @@ public class ConfigProfile
@Setter
private long memberExpireDays;
@Getter
- @Setter(AccessLevel.PACKAGE)
- private boolean isMember;
+ @Setter
+ public boolean isMember;
@Getter
- @Setter(AccessLevel.PACKAGE)
+ @Setter
private String discordWebhookUrl;
@Getter
@Setter
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordGameEventType.java b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordGameEventType.java
index 5419a3a5cb7..55633b94a50 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordGameEventType.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordGameEventType.java
@@ -90,7 +90,7 @@ enum DiscordGameEventType
BOSS_SARACHNIS("Sarachnis", DiscordAreaType.BOSSES, 7322),
BOSS_SKOTIZO("Skotizo", DiscordAreaType.BOSSES, 9048),
BOSS_SMOKE_DEVIL("Thermonuclear smoke devil", DiscordAreaType.BOSSES, 9363, 9619),
- BOSS_TEMPOROSS("Tempoross", DiscordAreaType.BOSSES, 12078),
+ BOSS_TEMPOROSS("Tempoross", DiscordAreaType.BOSSES, 12076),
BOSS_THE_LEVIATHAN("The Leviathan", DiscordAreaType.BOSSES, 8291),
BOSS_THE_ROYAL_TITANS("The Royal Titans", DiscordAreaType.BOSSES, 11669),
BOSS_THE_WHISPERER("The Whisperer", DiscordAreaType.BOSSES, 10595),
@@ -303,7 +303,7 @@ enum DiscordGameEventType
MG_BURTHORPE_GAMES_ROOM("Burthorpe Games Room", DiscordAreaType.MINIGAMES, 8781),
MG_CASTLE_WARS("Castle Wars", DiscordAreaType.MINIGAMES, 9520, 9620),
MG_CLAN_WARS("Clan Wars", DiscordAreaType.MINIGAMES, 12621, 12622, 12623, 13130, 13131, 13133, 13134, 13135, 13386, 13387, 13390, 13641, 13642, 13643, 13644, 13645, 13646, 13647, 13899, 13900, 14155, 14156),
- MG_PVP_ARENA("PvP Arena", DiscordAreaType.MINIGAMES, 13362, 13363),
+ MG_EMIRS_ARENA("Emir's Arena", DiscordAreaType.MINIGAMES, 13362, 13363),
MG_FISHING_TRAWLER("Fishing Trawler", DiscordAreaType.MINIGAMES, 7499),
MG_FORTIS_COLOSSEUM("Fortis Colosseum", DiscordAreaType.MINIGAMES, 7216),
MG_FORTIS_COLOSSEUM_LOBBY("Fortis Colosseum Lobby", DiscordAreaType.MINIGAMES, 7316),
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fairyring/FairyRingPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/fairyring/FairyRingPlugin.java
index 5220418c27a..6aba4ce7f0d 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/fairyring/FairyRingPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/fairyring/FairyRingPlugin.java
@@ -193,7 +193,7 @@ else if ("fairyringFilterDbrow".equals(ev.getEventName()))
tags = ring.getTags();
}
- var filter = client.getVarcStrValue(VarClientID.MESLAYERINPUT);
+ var filter = client.getVarcStrValue(VarClientID.MESLAYERINPUT).toLowerCase();
if (code.toLowerCase().contains(filter)
|| tags != null && tags.contains(filter)
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/FacePrioritySorter.java b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/FacePrioritySorter.java
index 95ed01b7720..628caa8fb53 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/FacePrioritySorter.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/FacePrioritySorter.java
@@ -396,10 +396,6 @@ private int pushFace(Model model, int face, IntBuffer opaqueBuffer, IntBuffer al
final byte overrideLum = model.getOverrideLuminance();
final short[] faceTextures = model.getFaceTextures();
- final byte[] textureFaces = model.getTextureFaces();
- final int[] texIndices1 = model.getTexIndices1();
- final int[] texIndices2 = model.getTexIndices2();
- final int[] texIndices3 = model.getTexIndices3();
final byte[] transparencies = model.getFaceTransparencies();
final byte[] bias = model.getFaceBias();
@@ -442,21 +438,16 @@ private int pushFace(Model model, int face, IntBuffer opaqueBuffer, IntBuffer al
float vy3 = modelLocalY[triangleC];
float vz3 = modelLocalZ[triangleC];
- int texA, texB, texC;
+ SceneUploader.computeFaceUvs(model, face);
- if (textureFaces != null && textureFaces[face] != -1)
- {
- int tface = textureFaces[face] & 0xff;
- texA = texIndices1[tface];
- texB = texIndices2[tface];
- texC = texIndices3[tface];
- }
- else
- {
- texA = triangleA;
- texB = triangleB;
- texC = triangleC;
- }
+ int su0 = (int) (SceneUploader.u0 * 256f);
+ int sv0 = (int) (SceneUploader.v0 * 256f);
+
+ int su1 = (int) (SceneUploader.u1 * 256f);
+ int sv1 = (int) (SceneUploader.v1 * 256f);
+
+ int su2 = (int) (SceneUploader.u2 * 256f);
+ int sv2 = (int) (SceneUploader.v2 * 256f);
int alphaBias = 0;
alphaBias |= transparencies != null ? (transparencies[face] & 0xff) << 24 : 0;
@@ -466,13 +457,13 @@ private int pushFace(Model model, int face, IntBuffer opaqueBuffer, IntBuffer al
var vb = alpha ? alphaBuffer : opaqueBuffer;
SceneUploader.putfff4(vb, vx1, vy1, vz1, alphaBias | color1);
- SceneUploader.put2222(vb, texture, (int) modelLocalX[texA] - (int) vx1, (int) modelLocalY[texA] - (int) vy1, (int) modelLocalZ[texA] - (int) vz1);
+ SceneUploader.put2222(vb, texture, su0, sv0, 0);
SceneUploader.putfff4(vb, vx2, vy2, vz2, alphaBias | color2);
- SceneUploader.put2222(vb, texture, (int) modelLocalX[texB] - (int) vx2, (int) modelLocalY[texB] - (int) vy2, (int) modelLocalZ[texB] - (int) vz2);
+ SceneUploader.put2222(vb, texture, su1, sv1, 0);
SceneUploader.putfff4(vb, vx3, vy3, vz3, alphaBias | color3);
- SceneUploader.put2222(vb, texture, (int) modelLocalX[texC] - (int) vx3, (int) modelLocalY[texC] - (int) vy3, (int) modelLocalZ[texC] - (int) vz3);
+ SceneUploader.put2222(vb, texture, su2, sv2, 0);
return 3;
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java
index 954578a7814..204810994fd 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java
@@ -130,7 +130,6 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
static final Shader PROGRAM = new Shader()
.add(GL_VERTEX_SHADER, "vert.glsl")
- .add(GL_GEOMETRY_SHADER, "geom.glsl")
.add(GL_FRAGMENT_SHADER, "frag.glsl");
static final Shader UI_PROGRAM = new Shader()
@@ -664,9 +663,18 @@ private void shutdownBuffers()
uniformBuffer = null;
Zone.freeBuffer();
- vaoO.free();
- vaoA.free();
- vaoPO.free();
+ if (vaoO != null)
+ {
+ vaoO.free();
+ }
+ if (vaoA != null)
+ {
+ vaoA.free();
+ }
+ if (vaoPO != null)
+ {
+ vaoPO.free();
+ }
vaoO = vaoA = vaoPO = null;
}
@@ -1032,6 +1040,8 @@ public void drawZoneOpaque(Projection entityProjection, Scene scene, int zx, int
checkGLErrors();
}
+ private static final int ALPHA_ZSORT_CLOSE = 2048;
+
@Override
public void drawZoneAlpha(Projection entityProjection, Scene scene, int level, int zx, int zz)
{
@@ -1053,13 +1063,17 @@ public void drawZoneAlpha(Projection entityProjection, Scene scene, int level, i
}
int offset = scene.getWorldViewId() == -1 ? (SCENE_OFFSET >> 3) : 0;
+ int dx = cameraX - ((zx - offset) << 10);
+ int dz = cameraZ - ((zz - offset) << 10);
+ boolean close = dx * dx + dz * dz < ALPHA_ZSORT_CLOSE * ALPHA_ZSORT_CLOSE;
+
if (level == 0)
{
z.alphaSort(zx - offset, zz - offset, cameraX, cameraY, cameraZ);
z.multizoneLocs(scene, zx - offset, zz - offset, cameraX, cameraZ, ctx.zones);
}
- z.renderAlpha(zx - offset, zz - offset, cameraYaw, cameraPitch, minLevel, this.level, maxLevel, level, hideRoofIds);
+ z.renderAlpha(zx - offset, zz - offset, cameraYaw, cameraPitch, minLevel, this.level, maxLevel, level, hideRoofIds, !close);
checkGLErrors();
}
@@ -1450,7 +1464,9 @@ private void drawUi(final int overlayColor, final int canvasHeight, final int ca
else
{
glDpiAwareViewport(0, 0, canvasWidth, canvasHeight);
- glUniform2i(uniTexTargetDimensions, canvasWidth, canvasHeight);
+ final GraphicsConfiguration graphicsConfiguration = clientUI.getGraphicsConfiguration();
+ final AffineTransform t = graphicsConfiguration.getDefaultTransform();
+ glUniform2i(uniTexTargetDimensions, getScaledValue(t.getScaleX(), canvasWidth), getScaledValue(t.getScaleY(), canvasHeight));
}
// Set the sampling function used when stretching the UI.
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/SceneUploader.java b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/SceneUploader.java
index aef8ad94549..a32aadb89b2 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/SceneUploader.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/SceneUploader.java
@@ -301,7 +301,8 @@ private int uploadZoneTile(Scene scene, Zone zone, Tile t, GpuIntBuffer vertexBu
SceneTileModel model = t.getSceneTileModel();
if (model != null && drawTile)
{
- len += upload(model, basex, basez, vertexBuffer);
+ Point tilePoint = t.getSceneLocation();
+ len += upload(model, tilePoint.getX() << 7, tilePoint.getY() << 7, vertexBuffer);
}
WallObject wallObject = t.getWallObject();
@@ -494,44 +495,22 @@ private int upload(Scene scene, SceneTilePaint tile, int tileZ, int tileX, int t
int tex = tile.getTexture() + 1;
vertexBuffer.put22224(lx2, ly2, lz2, hsl2);
- if (tile.isFlat())
- {
- vertexBuffer.put2222(tex, lx0 - lx2, ly0 - ly2, lz0 - lz2);
- }
- else
- {
- vertexBuffer.put2222(tex, lx2 - lx2, ly2 - ly2, lz2 - lz2);
- }
+ vertexBuffer.put2222(tex, 256, 256, 0);
vertexBuffer.put22224(lx3, ly3, lz3, hsl3);
- if (tile.isFlat())
- {
- vertexBuffer.put2222(tex, lx1 - lx3, ly1 - ly3, lz1 - lz3);
- }
- else
- {
- vertexBuffer.put2222(tex, lx3 - lx3, ly3 - ly3, lz3 - lz3);
- }
-
+ vertexBuffer.put2222(tex, 0, 256, 0);
vertexBuffer.put22224(lx1, ly1, lz1, hsl1);
- if (tile.isFlat())
- {
- vertexBuffer.put2222(tex, lx3 - lx1, ly3 - ly1, lz3 - lz1);
- }
- else
- {
- vertexBuffer.put2222(tex, lx1 - lx1, ly1 - ly1, lz1 - lz1);
- }
+ vertexBuffer.put2222(tex, 256, 0, 0);
vertexBuffer.put22224(lx0, ly0, lz0, hsl0);
- vertexBuffer.put2222(tex, lx0 - lx0, ly0 - ly0, lz0 - lz0);
+ vertexBuffer.put2222(tex, 0, 0, 0);
vertexBuffer.put22224(lx1, ly1, lz1, hsl1);
- vertexBuffer.put2222(tex, lx1 - lx1, ly1 - ly1, lz1 - lz1);
+ vertexBuffer.put2222(tex, 256, 0, 0);
vertexBuffer.put22224(lx3, ly3, lz3, hsl3);
- vertexBuffer.put2222(tex, lx3 - lx3, ly3 - ly3, lz3 - lz3);
+ vertexBuffer.put2222(tex, 0, 256, 0);
return 6;
}
@@ -573,48 +552,27 @@ private int upload(SceneTileModel sceneTileModel, int lx, int lz, GpuIntBuffer v
cnt += 3;
// vertexes are stored in scene local, convert to tile local
- int lx0 = vertexX[vertex0] - lx;
+ int lx0 = vertexX[vertex0] - basex;
int ly0 = vertexY[vertex0];
- int lz0 = vertexZ[vertex0] - lz;
+ int lz0 = vertexZ[vertex0] - basez;
- int lx1 = vertexX[vertex1] - lx;
+ int lx1 = vertexX[vertex1] - basex;
int ly1 = vertexY[vertex1];
- int lz1 = vertexZ[vertex1] - lz;
+ int lz1 = vertexZ[vertex1] - basez;
- int lx2 = vertexX[vertex2] - lx;
+ int lx2 = vertexX[vertex2] - basex;
int ly2 = vertexY[vertex2];
- int lz2 = vertexZ[vertex2] - lz;
+ int lz2 = vertexZ[vertex2] - basez;
int tex = triangleTextures != null ? triangleTextures[i] + 1 : 0;
vertexBuffer.put22224(lx0, ly0, lz0, hsl0);
- if (sceneTileModel.isFlat())
- {
- vertexBuffer.put2222(tex, vertexX[0] - lx - lx0, vertexY[0] - ly0, vertexZ[0] - lz - lz0);
- }
- else
- {
- vertexBuffer.put2222(tex, vertexX[vertex0] - lx - lx0, vertexY[vertex0] - ly0, vertexZ[vertex0] - lz - lz0);
- }
+ vertexBuffer.put2222(tex, (int) ((vertexX[vertex0] - lx) * 2f), (int) ((vertexZ[vertex0] - lz) * 2f), 0);
vertexBuffer.put22224(lx1, ly1, lz1, hsl1);
- if (sceneTileModel.isFlat())
- {
- vertexBuffer.put2222(tex, vertexX[1] - lx - lx1, vertexY[1] - ly1, vertexZ[1] - lz - lz1);
- }
- else
- {
- vertexBuffer.put2222(tex, vertexX[vertex1] - lx - lx1, vertexY[vertex1] - ly1, vertexZ[vertex1] - lz - lz1);
- }
+ vertexBuffer.put2222(tex, (int) ((vertexX[vertex1] - lx) * 2f), (int) ((vertexZ[vertex1] - lz) * 2f), 0);
vertexBuffer.put22224(lx2, ly2, lz2, hsl2);
- if (sceneTileModel.isFlat())
- {
- vertexBuffer.put2222(tex, vertexX[3] - lx - lx2, vertexY[3] - ly2, vertexZ[3] - lz - lz2);
- }
- else
- {
- vertexBuffer.put2222(tex, vertexX[vertex2] - lx - lx2, vertexY[vertex2] - ly2, vertexZ[vertex2] - lz - lz2);
- }
+ vertexBuffer.put2222(tex, (int) ((vertexX[vertex2] - lx) * 2f), (int) ((vertexZ[vertex2] - lz) * 2f), 0);
}
return cnt;
@@ -639,10 +597,6 @@ private int uploadStaticModel(Model model, int orient, int x, int y, int z, GpuI
final int[] color3s = model.getFaceColors3();
final short[] faceTextures = model.getFaceTextures();
- final byte[] textureFaces = model.getTextureFaces();
- final int[] texIndices1 = model.getTexIndices1();
- final int[] texIndices2 = model.getTexIndices2();
- final int[] texIndices3 = model.getTexIndices3();
final byte[] transparencies = model.getFaceTransparencies();
final byte[] bias = model.getFaceBias();
@@ -711,21 +665,16 @@ else if (color3 == -2)
int vy3 = modelLocalYI[triangleC];
int vz3 = modelLocalZI[triangleC];
- int texA, texB, texC;
+ computeFaceUvs(model, face);
- if (textureFaces != null && textureFaces[face] != -1)
- {
- int tface = textureFaces[face] & 0xff;
- texA = texIndices1[tface];
- texB = texIndices2[tface];
- texC = texIndices3[tface];
- }
- else
- {
- texA = triangleA;
- texB = triangleB;
- texC = triangleC;
- }
+ int su0 = (int) (u0 * 256f);
+ int sv0 = (int) (v0 * 256f);
+
+ int su1 = (int) (u1 * 256f);
+ int sv1 = (int) (v1 * 256f);
+
+ int su2 = (int) (u2 * 256f);
+ int sv2 = (int) (v2 * 256f);
int alphaBias = 0;
alphaBias |= transparencies != null ? (transparencies[face] & 0xff) << 24 : 0;
@@ -734,13 +683,13 @@ else if (color3 == -2)
GpuIntBuffer buf = alpha ? ab : vb;
buf.put22224(vx1, vy1, vz1, alphaBias | color1);
- buf.put2222(texture, modelLocalXI[texA] - vx1, modelLocalYI[texA] - vy1, modelLocalZI[texA] - vz1);
+ buf.put2222(texture, su0, sv0, 0);
buf.put22224(vx2, vy2, vz2, alphaBias | color2);
- buf.put2222(texture, modelLocalXI[texB] - vx2, modelLocalYI[texB] - vy2, modelLocalZI[texB] - vz2);
+ buf.put2222(texture, su1, sv1, 0);
buf.put22224(vx3, vy3, vz3, alphaBias | color3);
- buf.put2222(texture, modelLocalXI[texC] - vx3, modelLocalYI[texC] - vy3, modelLocalZI[texC] - vz3);
+ buf.put2222(texture, su2, sv2, 0);
len += 3;
}
@@ -767,10 +716,6 @@ static int uploadTempModel(Model model, int orientation, int x, int y, int z, In
final int[] color3s = model.getFaceColors3();
final short[] faceTextures = model.getFaceTextures();
- final byte[] textureFaces = model.getTextureFaces();
- final int[] texIndices1 = model.getTexIndices1();
- final int[] texIndices2 = model.getTexIndices2();
- final int[] texIndices3 = model.getTexIndices3();
final byte[] bias = model.getFaceBias();
@@ -852,34 +797,29 @@ else if (color3 == -2)
float vy3 = modelLocalY[triangleC];
float vz3 = modelLocalZ[triangleC];
- int texA, texB, texC;
+ computeFaceUvs(model, face);
- if (textureFaces != null && textureFaces[face] != -1)
- {
- int tface = textureFaces[face] & 0xff;
- texA = texIndices1[tface];
- texB = texIndices2[tface];
- texC = texIndices3[tface];
- }
- else
- {
- texA = triangleA;
- texB = triangleB;
- texC = triangleC;
- }
+ int su0 = (int) (u0 * 256f);
+ int sv0 = (int) (v0 * 256f);
+
+ int su1 = (int) (u1 * 256f);
+ int sv1 = (int) (v1 * 256f);
+
+ int su2 = (int) (u2 * 256f);
+ int sv2 = (int) (v2 * 256f);
int alphaBias = 0;
alphaBias |= bias != null ? (bias[face] & 0xff) << 16 : 0;
int texture = faceTextures != null ? faceTextures[face] + 1 : 0;
putfff4(opaqueBuffer, vx1, vy1, vz1, alphaBias | color1);
- put2222(opaqueBuffer, texture, (int) modelLocalX[texA] - (int) vx1, (int) modelLocalY[texA] - (int) vy1, (int) modelLocalZ[texA] - (int) vz1);
+ put2222(opaqueBuffer, texture, su0, sv0, 0);
putfff4(opaqueBuffer, vx2, vy2, vz2, alphaBias | color2);
- put2222(opaqueBuffer, texture, (int) modelLocalX[texB] - (int) vx2, (int) modelLocalY[texB] - (int) vy2, (int) modelLocalZ[texB] - (int) vz2);
+ put2222(opaqueBuffer, texture, su1, sv1, 0);
putfff4(opaqueBuffer, vx3, vy3, vz3, alphaBias | color3);
- put2222(opaqueBuffer, texture, (int) modelLocalX[texC] - (int) vx3, (int) modelLocalY[texC] - (int) vy3, (int) modelLocalZ[texC] - (int) vz3);
+ put2222(opaqueBuffer, texture, su2, sv2, 0);
len += 3;
}
@@ -924,4 +864,129 @@ static int interpolateHSL(int hsl, byte hue2, byte sat2, byte lum2, byte lerp)
return (hue << 10 | sat << 7 | lum) & 65535;
}
+
+ static float u0, u1, u2, v0, v1, v2;
+
+ static void computeFaceUvs(Model model, int face)
+ {
+ final float[] vertexX = model.getVerticesX();
+ final float[] vertexY = model.getVerticesY();
+ final float[] vertexZ = model.getVerticesZ();
+
+ final int[] indices1 = model.getFaceIndices1();
+ final int[] indices2 = model.getFaceIndices2();
+ final int[] indices3 = model.getFaceIndices3();
+
+ final byte[] textureFaces = model.getTextureFaces();
+ final int[] texIndices1 = model.getTexIndices1();
+ final int[] texIndices2 = model.getTexIndices2();
+ final int[] texIndices3 = model.getTexIndices3();
+
+ if (textureFaces != null && textureFaces[face] != -1)
+ {
+ final int triangleA = indices1[face];
+ final int triangleB = indices2[face];
+ final int triangleC = indices3[face];
+
+ int tfaceIdx = textureFaces[face] & 0xff;
+ int texA = texIndices1[tfaceIdx];
+ int texB = texIndices2[tfaceIdx];
+ int texC = texIndices3[tfaceIdx];
+
+ // v1 = vertex[texA]
+ float v1x = vertexX[texA];
+ float v1y = vertexY[texA];
+ float v1z = vertexZ[texA];
+ // v2 = vertex[texB] - v1
+ float v2x = vertexX[texB] - v1x;
+ float v2y = vertexY[texB] - v1y;
+ float v2z = vertexZ[texB] - v1z;
+ // v3 = vertex[texC] - v1
+ float v3x = vertexX[texC] - v1x;
+ float v3y = vertexY[texC] - v1y;
+ float v3z = vertexZ[texC] - v1z;
+
+ // v4 = vertex[triangleA] - v1
+ float v4x = vertexX[triangleA] - v1x;
+ float v4y = vertexY[triangleA] - v1y;
+ float v4z = vertexZ[triangleA] - v1z;
+ // v5 = vertex[triangleB] - v1
+ float v5x = vertexX[triangleB] - v1x;
+ float v5y = vertexY[triangleB] - v1y;
+ float v5z = vertexZ[triangleB] - v1z;
+ // v6 = vertex[triangleC] - v1
+ float v6x = vertexX[triangleC] - v1x;
+ float v6y = vertexY[triangleC] - v1y;
+ float v6z = vertexZ[triangleC] - v1z;
+
+ // v7 = v2 x v3
+ float v7x = v2y * v3z - v2z * v3y;
+ float v7y = v2z * v3x - v2x * v3z;
+ float v7z = v2x * v3y - v2y * v3x;
+
+ // v8 = v3 x v7
+ float v8x = v3y * v7z - v3z * v7y;
+ float v8y = v3z * v7x - v3x * v7z;
+ float v8z = v3x * v7y - v3y * v7x;
+
+ // f = 1 / (v8 ⋅ v2)
+ float f = 1.0F / (v8x * v2x + v8y * v2y + v8z * v2z);
+
+ // u0 = (v8 ⋅ v4) * f
+ u0 = (v8x * v4x + v8y * v4y + v8z * v4z) * f;
+ // u1 = (v8 ⋅ v5) * f
+ u1 = (v8x * v5x + v8y * v5y + v8z * v5z) * f;
+ // u2 = (v8 ⋅ v6) * f
+ u2 = (v8x * v6x + v8y * v6y + v8z * v6z) * f;
+
+ // v8 = v2 x v7
+ v8x = v2y * v7z - v2z * v7y;
+ v8y = v2z * v7x - v2x * v7z;
+ v8z = v2x * v7y - v2y * v7x;
+
+ // f = 1 / (v8 ⋅ v3)
+ f = 1.0F / (v8x * v3x + v8y * v3y + v8z * v3z);
+
+ // v0 = (v8 ⋅ v4) * f
+ v0 = (v8x * v4x + v8y * v4y + v8z * v4z) * f;
+ // v1 = (v8 ⋅ v5) * f
+ v1 = (v8x * v5x + v8y * v5y + v8z * v5z) * f;
+ // v2 = (v8 ⋅ v6) * f
+ v2 = (v8x * v6x + v8y * v6y + v8z * v6z) * f;
+ }
+ else
+ {
+ // Without a texture face, the client assigns tex = triangle, but the resulting
+ // calculations can be reduced:
+ //
+ // v1 = vertex[texA]
+ // v2 = vertex[texB] - v1
+ // v3 = vertex[texC] - v1
+ //
+ // v4 = 0
+ // v5 = v2
+ // v6 = v3
+ //
+ // v7 = v2 x v3
+ //
+ // v8 = v3 x v7
+ // u0 = (v8 . v4) / (v8 . v2) // 0 because v4 is 0
+ // u1 = (v8 . v5) / (v8 . v2) // 1 because v5=v2
+ // u2 = (v8 . v6) / (v8 . v2) // 0 because v8 is perpendicular to v3/v6
+ //
+ // v8 = v2 x v7
+ // v0 = (v8 . v4) / (v8 ⋅ v3) // 0 because v4 is 0
+ // v1 = (v8 . v5) / (v8 ⋅ v3) // 0 because v8 is perpendicular to v5/v2
+ // v2 = (v8 . v6) / (v8 ⋅ v3) // 1 because v6=v3
+
+ u0 = 0f;
+ v0 = 0f;
+
+ u1 = 1f;
+ v1 = 0f;
+
+ u2 = 0f;
+ v2 = 1f;
+ }
+ }
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/VBO.java b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/VBO.java
index 42935ab3695..8e0aa13f361 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/VBO.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/VBO.java
@@ -31,6 +31,7 @@
class VBO
{
final int size;
+ private int usage;
int bufId;
private ByteBuffer buffer;
IntBuffer vb;
@@ -44,6 +45,7 @@ class VBO
void init(int usage)
{
+ this.usage = usage;
bufId = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, bufId);
@@ -68,7 +70,7 @@ void map()
{
assert !mapped;
glBindBuffer(GL_ARRAY_BUFFER, bufId);
- buffer = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY, buffer);
+ buffer = glMapBufferRange(GL_ARRAY_BUFFER, 0, size, GL_MAP_WRITE_BIT | (usage == GL_STATIC_DRAW ? 0 : (GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT)), buffer);
if (buffer == null)
{
throw new RuntimeException("unable to map GL buffer " + bufId + " size " + size);
@@ -85,6 +87,10 @@ void unmap()
vb = null;
glBindBuffer(GL_ARRAY_BUFFER, bufId);
+ if (usage != GL_STATIC_DRAW)
+ {
+ glFlushMappedBufferRange(GL_ARRAY_BUFFER, 0, (long) len * Integer.BYTES);
+ }
glUnmapBuffer(GL_ARRAY_BUFFER);
glBindBuffer(GL_ARRAY_BUFFER, 0);
mapped = false;
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/Zone.java b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/Zone.java
index 783772fe639..ea2c7a46d54 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/Zone.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/Zone.java
@@ -48,8 +48,6 @@
@RequiredArgsConstructor
class Zone
{
- private static final boolean USE_STATIC_UNSORTED = false;
-
// Zone vertex format
// index 0: short vec3(x, y, z)
// index 1: int abhsl
@@ -511,7 +509,7 @@ void alphaSort(int zx, int zz, int cx, int cy, int cz)
);
}
- void renderAlpha(int zx, int zz, int cyaw, int cpitch, int minLevel, int currentLevel, int maxLevel, int level, Set hiddenRoofIds)
+ void renderAlpha(int zx, int zz, int cyaw, int cpitch, int minLevel, int currentLevel, int maxLevel, int level, Set hiddenRoofIds, boolean useStaticUnsorted)
{
drawOff.clear();
drawEnd.clear();
@@ -561,7 +559,7 @@ void renderAlpha(int zx, int zz, int cyaw, int cpitch, int minLevel, int current
continue;
}
- if (USE_STATIC_UNSORTED)
+ if (useStaticUnsorted)
{
lastDrawMode = STATIC_UNSORTED;
pushRange(m.startpos, m.endpos);
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/Script.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/Script.java
index c76282a5a7e..243cf3fb144 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/Script.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/Script.java
@@ -3,20 +3,14 @@
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.coords.WorldPoint;
-import net.runelite.client.plugins.microbot.globval.enums.InterfaceTab;
import net.runelite.client.plugins.microbot.shortestpath.ShortestPathPlugin;
import net.runelite.client.plugins.microbot.util.Global;
import net.runelite.client.plugins.microbot.util.cache.Rs2CacheManager;
import net.runelite.client.plugins.microbot.util.inventory.Rs2Inventory;
-import net.runelite.client.plugins.microbot.util.keyboard.Rs2Keyboard;
import net.runelite.client.plugins.microbot.util.player.Rs2Player;
-import net.runelite.client.plugins.microbot.util.tabs.Rs2Tab;
import net.runelite.client.plugins.microbot.util.walker.Rs2Walker;
-import net.runelite.client.plugins.microbot.util.widget.Rs2Widget;
import org.jetbrains.annotations.NotNull;
-import java.time.Duration;
-import java.time.Instant;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
@@ -37,8 +31,6 @@ public Thread newThread(@NotNull Runnable r) {
});
protected ScheduledFuture> scheduledFuture;
protected ScheduledFuture> mainScheduledFuture;
- @Deprecated(since = "1.9.7 - Blocking events are now handling turning off the level up dialog", forRemoval = true)
- public static boolean hasLeveledUp = false;
public boolean isRunning() {
return mainScheduledFuture != null && !mainScheduledFuture.isDone();
@@ -46,17 +38,6 @@ public boolean isRunning() {
@Getter
protected static WorldPoint initialPlayerLocation;
- public Instant startTime;
-
- /**
- * Get the total runtime of the script
- *
- * @return the total runtime of the script
- */
- public Duration getRunTime() {
- if (startTime == null) return Duration.ofSeconds(0);
- return Duration.between(startTime, Instant.now());
- }
public void shutdown() {
if (mainScheduledFuture != null && !mainScheduledFuture.isDone()) {
@@ -73,14 +54,9 @@ public void shutdown() {
if (scheduledFuture != null && !scheduledFuture.isDone()) {
scheduledFuture.cancel(true);
}
- startTime = null;
}
public boolean run() {
- if (startTime == null) {
- startTime = Instant.now();
- //init - things that have to be checked once can be added here
- }
//Avoid executing any blocking events if the player hasn't finished Tutorial Island
if (Microbot.isLoggedIn() && !Rs2Player.hasCompletedTutorialIsland())
return true;
@@ -109,17 +85,4 @@ public boolean run() {
}
return true;
}
-
- @Deprecated(since = "1.6.9 - Use Rs2Keyboard.keyPress", forRemoval = true)
- public void keyPress(char c) {
- Rs2Keyboard.keyPress(c);
- }
-
- @Deprecated(since = "Use Rs2Player.logout()", forRemoval = true)
- public void logout() {
- Rs2Tab.switchToLogout();
- sleepUntil(() -> Rs2Tab.getCurrentTab() == InterfaceTab.LOGOUT);
- sleep(600, 1000);
- Rs2Widget.clickWidget("Click here to logout");
- }
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExamplePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExamplePlugin.java
new file mode 100644
index 00000000000..e6b21e5b329
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExamplePlugin.java
@@ -0,0 +1,40 @@
+package net.runelite.client.plugins.microbot.example;
+
+import lombok.extern.slf4j.Slf4j;
+import net.runelite.client.eventbus.Subscribe;
+import net.runelite.client.events.ConfigChanged;
+import net.runelite.client.plugins.Plugin;
+import net.runelite.client.plugins.PluginDescriptor;
+
+import javax.inject.Inject;
+import java.awt.*;
+
+@PluginDescriptor(
+ name = PluginDescriptor.Default + "Example Plugin",
+ description = "Performance test for GameObject composition retrieval",
+ tags = {"performance", "microbot", "test", "gameobject"},
+ enabledByDefault = false
+)
+@Slf4j
+public class ExamplePlugin extends Plugin {
+ @Inject
+ ExampleScript exampleScript;
+
+
+ @Override
+ protected void startUp() throws AWTException {
+
+ exampleScript.run();
+ }
+
+
+
+ protected void shutDown() {
+ exampleScript.shutdown();
+ }
+
+ // on settings change
+ @Subscribe
+ public void onConfigChanged(final ConfigChanged event) {
+ }
+}
\ No newline at end of file
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExampleScript.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExampleScript.java
new file mode 100644
index 00000000000..ca0e5d2ff74
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/example/ExampleScript.java
@@ -0,0 +1,84 @@
+package net.runelite.client.plugins.microbot.example;
+
+import lombok.extern.slf4j.Slf4j;
+import net.runelite.client.plugins.microbot.Microbot;
+import net.runelite.client.plugins.microbot.Script;
+import net.runelite.client.plugins.microbot.util.tileobject.Rs2TileObjectApi;
+import net.runelite.client.plugins.microbot.util.tileobject.Rs2TileObjectModel;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.stream.Collectors;
+
+/**
+ * Performance test script for measuring GameObject composition retrieval speed.
+ *
+ * This script runs every 5 seconds and performs the following:
+ * - Gets all GameObjects in the scene
+ * - Retrieves the ObjectComposition for each GameObject
+ * - Measures and logs the total time taken
+ * - Reports average time per object
+ *
+ * Useful for performance profiling and optimization testing.
+ */
+@Slf4j
+public class ExampleScript extends Script {
+
+ /**
+ * Main entry point for the performance test script.
+ */
+ public boolean run() {
+ mainScheduledFuture = scheduledExecutorService.scheduleWithFixedDelay(() -> {
+ try {
+ if (!Microbot.isLoggedIn()) return;
+
+ // Performance test: Loop over game objects and get compositions
+ long startTime = System.currentTimeMillis();
+ AtomicLong endTime = new AtomicLong();
+
+ var tileObjects = Microbot.getClientThread().invoke(() -> {
+ // List _tileObjects = Rs2TileObjectApi.getObjectsStream().filter(x -> x.getName() != null && !x.getName().isEmpty() && x.getName() != "null").collect(Collectors.toList());
+ Rs2TileObjectModel test = Rs2TileObjectApi.getNearest(tile -> tile.getName() != null && tile.getName().toLowerCase().contains("tree"));
+ endTime.set(System.currentTimeMillis());
+ System.out.println("Retrieved " + test.getName() + " game objects in " + (endTime.get() - startTime) + " ms");
+
+ /*for (Rs2TileObjectModel rs2TileObjectModel: _tileObjects) {
+ var name = rs2TileObjectModel.getName(); // Access name to simulate some processing
+ System.out.println("Object Name: " + name);
+ }
+*/
+ return Rs2TileObjectApi.getObjectsStream().collect(Collectors.toList());
+ });
+
+
+ int compositionCount = 0;
+
+ /*for (Rs2TileObjectModel tileObject : tileObjects) {
+ var name = tileObject.getName(); // Access name to simulate some processing
+ if (name != null) {
+ compositionCount++;
+ System.out.println("composition " + compositionCount + ": " + name);
+ }
+ }*/
+
+ endTime.set(System.currentTimeMillis());
+ long durationMs = (endTime.get() - startTime);
+
+/*
+ log.info("Performance Test Results:");
+ log.info(" Total GameObjects: {}", tileObjects.size());
+ log.info(" Compositions retrieved: {}", compositionCount);
+ log.info(" Time taken: {} ms", durationMs);
+ log.info(" Average time per object: {} μs",
+ tileObjects.size() > 0 ? (endTime.get() - startTime) / 1000 / tileObjects.size() : 0);
+*/
+
+ } catch (Exception ex) {
+ log.error("Error in performance test loop", ex);
+ }
+ }, 0, 5000, TimeUnit.MILLISECONDS);
+
+ return true;
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/gameobject/Rs2GameObject.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/gameobject/Rs2GameObject.java
index c19a693e75d..1d4b4dee52a 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/gameobject/Rs2GameObject.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/gameobject/Rs2GameObject.java
@@ -1747,7 +1747,7 @@ private static boolean clickObject(TileObject object) {
return clickObject(object, "");
}
- private static boolean clickObject(TileObject object, String action) {
+ public static boolean clickObject(TileObject object, String action) {
if (object == null) return false;
if (Microbot.getClient().getLocalPlayer().getWorldLocation().distanceTo(object.getWorldLocation()) > 51) {
Microbot.log("Object with id " + object.getId() + " is not close enough to interact with. Walking to the object....");
@@ -1902,7 +1902,9 @@ public static ObjectComposition getObjectComposition(int id) {
ObjectComposition objectComposition = Microbot.getClientThread().runOnClientThreadOptional(() -> Microbot.getClient().getObjectDefinition(id))
.orElse(null);
if (objectComposition == null) return null;
- return objectComposition.getImpostorIds() == null ? objectComposition : objectComposition.getImpostor();
+ return objectComposition.getImpostorIds() == null ?
+ objectComposition :
+ Microbot.getClientThread().runOnClientThreadOptional((objectComposition::getImpostor)).orElse(null);
}
public static boolean canWalkTo(TileObject tileObject, int distance) {
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/security/LoginManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/security/LoginManager.java
index 1fb5e1598bc..865e1247d1c 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/security/LoginManager.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/security/LoginManager.java
@@ -121,8 +121,7 @@ public static boolean login() {
log.warn("Cannot login - client is not initialised");
return false;
}
- int currentWorld = client.getWorld();
- int targetWorld = currentWorld > 300 ? currentWorld : getRandomWorld(getActiveProfile().isMember());
+ int targetWorld = getRandomWorld(getActiveProfile().isMember());
return login(getActiveProfile().getName(), getActiveProfile().getPassword(), targetWorld);
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/tileobject/Rs2TileObjectApi.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/tileobject/Rs2TileObjectApi.java
new file mode 100644
index 00000000000..be23e4a5b4c
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/tileobject/Rs2TileObjectApi.java
@@ -0,0 +1,102 @@
+package net.runelite.client.plugins.microbot.util.tileobject;
+
+import net.runelite.api.GameObject;
+import net.runelite.api.Player;
+import net.runelite.api.Tile;
+import net.runelite.api.coords.WorldPoint;
+import net.runelite.client.plugins.microbot.Microbot;
+import net.runelite.client.plugins.microbot.util.gameobject.Rs2GameObject;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+/**
+ * API for interacting with tile objects in the game world.
+ */
+public class Rs2TileObjectApi {
+
+ private static int lastUpdateObjects = 0;
+ private static List tileObjects = new ArrayList<>();
+
+ /**
+ * Get all tile objects in the current scene
+ * @return Stream of Rs2TileObjectModel
+ */
+ public static Stream getObjectsStream() {
+
+ if (lastUpdateObjects >= Microbot.getClient().getTickCount()) {
+ return tileObjects.stream();
+ }
+
+ Player player = Microbot.getClient().getLocalPlayer();
+ if (player == null) return Stream.empty();
+
+ List result = new ArrayList<>();
+
+ var tileValues = Microbot.getClient().getTopLevelWorldView().getScene().getTiles()[Microbot.getClient().getTopLevelWorldView().getPlane()];
+
+ for (Tile[] tileValue : tileValues) {
+ for (Tile tile : tileValue) {
+ if (tile == null) continue;
+
+ if (tile.getGameObjects() != null) {
+ for (GameObject gameObject : tile.getGameObjects()) {
+ if (gameObject == null) continue;
+ if (gameObject.getSceneMinLocation().equals(tile.getSceneLocation())) {
+ result.add(new Rs2TileObjectModel(gameObject));
+ }
+ }
+ }
+ if (tile.getGroundObject() != null) {
+ result.add(new Rs2TileObjectModel(tile.getGroundObject()));
+ }
+ if (tile.getWallObject() != null) {
+ result.add(new Rs2TileObjectModel(tile.getWallObject()));
+ }
+ if (tile.getDecorativeObject() != null) {
+ result.add(new Rs2TileObjectModel(tile.getDecorativeObject()));
+ }
+ }
+ }
+
+ tileObjects = result;
+ lastUpdateObjects = Microbot.getClient().getTickCount();
+ return result.stream();
+ }
+
+ /**
+ * Returns the nearest tile object matching the supplied predicate, or null if none match.
+ * Distance is based on straight-line world tile distance from the local player.
+ *
+ * @return nearest matching Rs2TileObjectModel or null
+ */
+ public static Rs2TileObjectModel getNearest() {
+ return getNearest(null);
+ }
+
+ /**
+ * Returns the nearest tile object matching the supplied predicate, or null if none match.
+ * Distance is based on straight-line world tile distance from the local player.
+ *
+ * @param filter predicate to test objects
+ * @return nearest matching Rs2TileObjectModel or null
+ */
+ public static Rs2TileObjectModel getNearest(Predicate filter) {
+ Player player = Microbot.getClient().getLocalPlayer();
+ if (player == null) return null;
+
+ WorldPoint playerLoc = player.getWorldLocation();
+
+ Stream stream = getObjectsStream();
+ if (filter != null) {
+ stream = stream.filter(filter);
+ }
+
+ return stream
+ .min(Comparator.comparingInt(o -> o.getWorldLocation().distanceTo(playerLoc)))
+ .orElse(null);
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/tileobject/Rs2TileObjectModel.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/tileobject/Rs2TileObjectModel.java
new file mode 100644
index 00000000000..f67e90dc374
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/tileobject/Rs2TileObjectModel.java
@@ -0,0 +1,265 @@
+package net.runelite.client.plugins.microbot.util.tileobject;
+
+import lombok.Getter;
+import net.runelite.api.*;
+import net.runelite.api.Point;
+import net.runelite.api.coords.LocalPoint;
+import net.runelite.api.coords.WorldPoint;
+import net.runelite.client.plugins.microbot.Microbot;
+import net.runelite.client.plugins.microbot.util.camera.Rs2Camera;
+import net.runelite.client.plugins.microbot.util.equipment.Rs2Equipment;
+import net.runelite.client.plugins.microbot.util.gameobject.Rs2GameObject;
+import net.runelite.client.plugins.microbot.util.menu.NewMenuEntry;
+import net.runelite.client.plugins.microbot.util.misc.Rs2UiHelper;
+import net.runelite.client.plugins.microbot.util.walker.Rs2Walker;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.awt.*;
+
+import static net.runelite.client.plugins.microbot.util.Global.sleepUntil;
+
+
+public class Rs2TileObjectModel implements TileObject {
+
+ public Rs2TileObjectModel(GameObject gameObject) {
+ this.tileObject = gameObject;
+ this.tileObjectType = TileObjectType.GAME;
+ }
+
+ public Rs2TileObjectModel(DecorativeObject tileObject) {
+ this.tileObject = tileObject;
+ this.tileObjectType = TileObjectType.DECORATIVE;
+ }
+
+ public Rs2TileObjectModel(WallObject tileObject) {
+ this.tileObject = tileObject;
+ this.tileObjectType = TileObjectType.WALL;
+ }
+
+ public Rs2TileObjectModel(GroundObject tileObject) {
+ this.tileObject = tileObject;
+ this.tileObjectType = TileObjectType.GROUND;
+ }
+
+ public Rs2TileObjectModel(TileObject tileObject) {
+ this.tileObject = tileObject;
+ this.tileObjectType = TileObjectType.GENERIC;
+ }
+
+ @Getter
+ private final TileObjectType tileObjectType;
+ private final TileObject tileObject;
+ private String[] actions;
+
+
+ @Override
+ public long getHash() {
+ return tileObject.getHash();
+ }
+
+ @Override
+ public int getX() {
+ return tileObject.getX();
+ }
+
+ @Override
+ public int getY() {
+ return tileObject.getY();
+ }
+
+ @Override
+ public int getZ() {
+ return tileObject.getZ();
+ }
+
+ @Override
+ public int getPlane() {
+ return tileObject.getPlane();
+ }
+
+ @Override
+ public WorldView getWorldView() {
+ return tileObject.getWorldView();
+ }
+
+ public int getId() {
+ return tileObject.getId();
+ }
+
+ @Override
+ public @NotNull WorldPoint getWorldLocation() {
+ return tileObject.getWorldLocation();
+ }
+
+ public String getName() {
+ return Microbot.getClientThread().invoke(() -> {
+ ObjectComposition composition = Microbot.getClient().getObjectDefinition(tileObject.getId());
+ if(composition.getImpostorIds() != null)
+ {
+ composition = composition.getImpostor();
+ }
+ if(composition == null)
+ return null;
+ return Rs2UiHelper.stripColTags(composition.getName());
+ });
+ }
+
+ @Override
+ public @NotNull LocalPoint getLocalLocation() {
+ return tileObject.getLocalLocation();
+ }
+
+ @Override
+ public @Nullable Point getCanvasLocation() {
+ return tileObject.getCanvasLocation();
+ }
+
+ @Override
+ public @Nullable Point getCanvasLocation(int zOffset) {
+ return tileObject.getCanvasLocation();
+ }
+
+ @Override
+ public @Nullable Polygon getCanvasTilePoly() {
+ return tileObject.getCanvasTilePoly();
+ }
+
+ @Override
+ public @Nullable Point getCanvasTextLocation(Graphics2D graphics, String text, int zOffset) {
+ return tileObject.getCanvasTextLocation(graphics, text, zOffset);
+ }
+
+ @Override
+ public @Nullable Point getMinimapLocation() {
+ return tileObject.getMinimapLocation();
+ }
+
+ @Override
+ public @Nullable Shape getClickbox() {
+ return tileObject.getClickbox();
+ }
+
+ public ObjectComposition getObjectComposition() {
+ return Microbot.getClientThread().invoke(() -> {
+ ObjectComposition composition = Microbot.getClient().getObjectDefinition(tileObject.getId());
+ if(composition.getImpostorIds() != null)
+ {
+ composition = composition.getImpostor();
+ }
+ return composition;
+ });
+ }
+
+ /**
+ * Clicks on the specified tile object with no specific action.
+ * Delegates to Rs2GameObject.clickObject.
+ *
+ * @param action the action to perform (e.g., "Open", "Climb")
+ * @return true if the interaction was successful, false otherwise
+ */
+ public boolean click(String action) {
+ if (Microbot.getClient().getLocalPlayer().getWorldLocation().distanceTo(getWorldLocation()) > 51) {
+ Microbot.log("Object with id " + getId() + " is not close enough to interact with. Walking to the object....");
+ Rs2Walker.walkTo(getWorldLocation());
+ return false;
+ }
+
+ try {
+
+ int param0;
+ int param1;
+ MenuAction menuAction = MenuAction.WALK;
+
+
+ Microbot.status = action + " " + getName();
+
+ if (getTileObjectType() == TileObjectType.GAME) {
+ GameObject obj = (GameObject) tileObject;
+ if (obj.sizeX() > 1) {
+ param0 = obj.getLocalLocation().getSceneX() - obj.sizeX() / 2;
+ } else {
+ param0 = obj.getLocalLocation().getSceneX();
+ }
+
+ if (obj.sizeY() > 1) {
+ param1 = obj.getLocalLocation().getSceneY() - obj.sizeY() / 2;
+ } else {
+ param1 = obj.getLocalLocation().getSceneY();
+ }
+ } else {
+ // Default objects like walls, groundobjects, decorationobjects etc...
+ param0 = getLocalLocation().getSceneX();
+ param1 = getLocalLocation().getSceneY();
+ }
+
+
+ int index = 0;
+ String objName = "";
+ if (action != null) {
+ //performance improvement to only get compoisiton if action has been specified
+ var objComp = getObjectComposition();
+ String[] actions;
+ if (objComp.getImpostorIds() != null && objComp.getImpostor() != null) {
+ actions = objComp.getImpostor().getActions();
+ } else {
+ actions = objComp.getActions();
+ }
+
+ for (int i = 0; i < actions.length; i++) {
+ if (actions[i] == null) continue;
+ if (action.equalsIgnoreCase(Rs2UiHelper.stripColTags(actions[i]))) {
+ index = i;
+ break;
+ }
+ }
+
+ if (index == actions.length)
+ index = 0;
+
+ objName = objComp.getName();
+
+ // both hands must be free before using MINECART
+ if (objComp.getName().toLowerCase().contains("train cart")) {
+ Rs2Equipment.unEquip(EquipmentInventorySlot.WEAPON);
+ Rs2Equipment.unEquip(EquipmentInventorySlot.SHIELD);
+ sleepUntil(() -> Rs2Equipment.get(EquipmentInventorySlot.WEAPON) == null && Rs2Equipment.get(EquipmentInventorySlot.SHIELD) == null);
+ }
+ }
+
+ if (index == -1) {
+ Microbot.log("Failed to interact with object " + getId() + " " + action);
+ }
+
+
+ if (Microbot.getClient().isWidgetSelected()) {
+ menuAction = MenuAction.WIDGET_TARGET_ON_GAME_OBJECT;
+ } else if (index == 0) {
+ menuAction = MenuAction.GAME_OBJECT_FIRST_OPTION;
+ } else if (index == 1) {
+ menuAction = MenuAction.GAME_OBJECT_SECOND_OPTION;
+ } else if (index == 2) {
+ menuAction = MenuAction.GAME_OBJECT_THIRD_OPTION;
+ } else if (index == 3) {
+ menuAction = MenuAction.GAME_OBJECT_FOURTH_OPTION;
+ } else if (index == 4) {
+ menuAction = MenuAction.GAME_OBJECT_FIFTH_OPTION;
+ }
+
+ if (!Rs2Camera.isTileOnScreen(getLocalLocation())) {
+ Rs2Camera.turnTo(tileObject);
+ }
+
+
+ Microbot.doInvoke(new NewMenuEntry(param0, param1, menuAction.getId(), getId(), -1, action, objName, tileObject), Rs2UiHelper.getObjectClickbox(tileObject));
+// MenuEntryImpl(getOption=Use, getTarget=Barrier, getIdentifier=43700, getType=GAME_OBJECT_THIRD_OPTION, getParam0=53, getParam1=51, getItemId=-1, isForceLeftClick=true, getWorldViewId=-1, isDeprioritized=false)
+ //Rs2Reflection.invokeMenu(param0, param1, menuAction.getId(), object.getId(),-1, "", "", -1, -1);
+
+ } catch (Exception ex) {
+ Microbot.log("Failed to interact with object " + ex.getMessage());
+ }
+
+ return true;
+ }
+
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/tileobject/TileObjectType.java b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/tileobject/TileObjectType.java
new file mode 100644
index 00000000000..a42306c061a
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/microbot/util/tileobject/TileObjectType.java
@@ -0,0 +1,9 @@
+package net.runelite.client.plugins.microbot.util.tileobject;
+
+public enum TileObjectType {
+ GAME,
+ WALL,
+ DECORATIVE,
+ GROUND,
+ GENERIC
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/EssencePouchOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/EssencePouchOverlay.java
index 55b159138df..31b440c4ca4 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/EssencePouchOverlay.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/EssencePouchOverlay.java
@@ -252,7 +252,8 @@ public void renderItemOverlay(Graphics2D g, int itemId, WidgetItem widgetItem)
if (pouch.getDegradation != null && config.pouchDegrade())
{
int breakpoint = pouch.nextDegradationBreakpoint(client);
- int remEss = durabilityToEssence(breakpoint - pouch.getDegradation(client));
+ int remDura = breakpoint - pouch.getDegradation(client);
+ int remEss = (pouch == EssPouch.COLOSSAL) ? remDura : durabilityToEssence(remDura);
int limit = pouch.maxAmount(client);
int remFills = (remEss + limit - 1) / limit;
if (degraded)
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/Task.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/Task.java
index c97f2be2e71..e698a971d70 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/Task.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/Task.java
@@ -98,7 +98,7 @@ public enum Task
GHOSTS("Ghosts", ItemID.AMULET_OF_GHOSTSPEAK, "Death wing", "Tortured soul", "Forgotten Soul", "Revenant"),
GHOULS("Ghouls", ItemID.TRICK_OR_TREAT_HEAD),
GIANT_MOLE("The Giant Mole", ItemID.MOLEPET),
- GOBLINS("Goblin", ItemID.ARCEUUS_CORPSE_GOBLIN_INITIAL, "Sergeant Strongstack", "Sergeant Grimspike", "Sergeant Steelwill"),
+ GOBLINS("Goblins", ItemID.ARCEUUS_CORPSE_GOBLIN_INITIAL, "Sergeant Strongstack", "Sergeant Grimspike", "Sergeant Steelwill"),
GREATER_DEMONS("Greater demons", ItemID.GREATER_DEMON_MASK, "K'ril Tsutsaroth", "Tstanon Karlak", "Skotizo", "Tormented Demon"),
GREEN_DRAGONS("Green dragons", ItemID.DRAGONMASK_GREEN, "Elvarg"),
GROTESQUE_GUARDIANS("The Grotesque Guardians", ItemID.DUSKPET, 0, ItemID.SLAYER_ROCK_HAMMER, "Dusk", "Dawn"),
@@ -114,7 +114,7 @@ public enum Task
JAD("TzTok-Jad", ItemID.JAD_PET),
JELLIES("Jellies", ItemID.SLAYERGUIDE_JELLY, "Jelly"),
JUNGLE_HORROR("Jungle horrors", ItemID.ARCEUUS_CORPSE_HORROR_INITIAL),
- KALPHITE("Kalphite", ItemID.POH_KALPHITE_SOLDIER),
+ KALPHITE("Kalphites", ItemID.POH_KALPHITE_SOLDIER),
KALPHITE_QUEEN("The Kalphite Queen", ItemID.KQPET_WALKING),
KILLERWATTS("Killerwatts", ItemID.SLAYERGUIDE_KILLERWATT),
KING_BLACK_DRAGON("The King Black Dragon", ItemID.KBDPET),
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/HunterAreaLocation.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/HunterAreaLocation.java
index bd4e509b0de..958d114a99e 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/HunterAreaLocation.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/HunterAreaLocation.java
@@ -35,7 +35,7 @@ enum HunterAreaLocation
{
ALDARIN_NORTH(new WorldPoint(1357, 2977, 0), HunterCreature.COPPER_LONGTAIL),
ALDARIN_WEST(new WorldPoint(1342, 2934, 0), HunterCreature.RUBY_HARVEST),
- AUBURNVALE_NORTH(new WorldPoint(1387, 3392, 0), HunterCreature.COMMON_KEBBIT),
+ AUBURNVALE_NORTH(new WorldPoint(1387, 3392, 0), HunterCreature.WILD_KEBBIT, HunterCreature.RUBY_HARVEST),
AUBURNVALE_WEST(new WorldPoint(1349, 3346, 0), HunterCreature.COPPER_LONGTAIL),
AVIUM_SAVANNAH(new WorldPoint(1616, 2999, 0), HunterCreature.PYRE_FOX),
AVIUM_SAVANNAH_EAST(new WorldPoint(1745, 3008, 0), HunterCreature.SUNLIGHT_ANTELOPE),
diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/gpu/geom.glsl b/runelite-client/src/main/resources/net/runelite/client/plugins/gpu/geom.glsl
deleted file mode 100644
index 6846c6f097b..00000000000
--- a/runelite-client/src/main/resources/net/runelite/client/plugins/gpu/geom.glsl
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (c) 2018, Adam
- * 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.
- */
-
-#version 330
-
-#include texture_config
-
-//#define ZBUF_DEBUG
-//#define BIAS_DEBUG
-
-// smallest unit of the texture which can be moved per tick. textures are all
-// 128x128px - so this is equivalent to +1px
-#define TEXTURE_ANIM_UNIT (1.0f / 128.0f)
-
-layout(triangles) in;
-layout(triangle_strip, max_vertices = 3) out;
-
-layout(std140) uniform uniforms {
- float cameraYaw;
- float cameraPitch;
- float cameraX;
- float cameraY;
- float cameraZ;
-};
-
-#include "uv.glsl"
-
-uniform vec2 textureAnimations[TEXTURE_COUNT];
-uniform int tick;
-uniform mat4 worldProj;
-
-in vec4 gVertex[3];
-in vec4 gColor[3];
-in float gHsl[3];
-in int gTextureId[3];
-in vec4 gTexPos[3];
-in float gFogAmount[3];
-in int gBias[3];
-
-out vec4 fColor;
-noperspective centroid out float fHsl;
-flat out int fTextureId;
-out vec2 fUv;
-out float fFogAmount;
-#ifdef ZBUF_DEBUG
-out float fDepth;
-#endif
-
-void main() {
- int textureId = gTextureId[0];
- vec2 uv[3];
-
- if (textureId > 0) {
- vec3 cameraPos = vec3(cameraX, cameraY, cameraZ);
- compute_uv(cameraPos, gVertex[0].xyz, gVertex[1].xyz, gVertex[2].xyz, gTexPos[0].xyz, gTexPos[1].xyz, gTexPos[2].xyz, uv[0], uv[1], uv[2]);
-
- vec2 textureAnim = textureAnimations[min(textureId - 1, TEXTURE_COUNT - 1)];
- for (int i = 0; i < 3; ++i) {
- uv[i] += tick * textureAnim * TEXTURE_ANIM_UNIT;
- }
- } else {
- uv[0] = vec2(0);
- uv[1] = vec2(0);
- uv[2] = vec2(0);
- }
-
- for (int i = 0; i < 3; ++i) {
-#ifdef BIAS_DEBUG
- fColor = vec4(clamp(gBias[i], 0, 12) / 12.0, 0.0, 0.0, 1.0);
-#else
- fColor = gColor[i];
-#endif
- fHsl = gHsl[i];
- fTextureId = gTextureId[i];
- fUv = uv[i];
- fFogAmount = gFogAmount[i];
-
- vec4 pos = worldProj * gVertex[i];
-#ifdef ZBUF_DEBUG
- fDepth = pos.z / pos.w;
-#endif
- pos.z += gBias[i] / 128.0;
- gl_Position = pos;
-
- EmitVertex();
- }
-
- EndPrimitive();
-}
\ No newline at end of file
diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/gpu/uv.glsl b/runelite-client/src/main/resources/net/runelite/client/plugins/gpu/uv.glsl
deleted file mode 100644
index 7818e59b2de..00000000000
--- a/runelite-client/src/main/resources/net/runelite/client/plugins/gpu/uv.glsl
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 2023, Adam
- * 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.
- */
-
-void compute_uv(vec3 cameraPos, vec3 f1, vec3 f2, vec3 f3, vec3 t1, vec3 t2, vec3 t3, out vec2 uv1, out vec2 uv2, out vec2 uv3) {
- vec3 tangent = t2 - t1;
- vec3 bitangent = t3 - t1;
-
- vec3 texNormal = cross(tangent, bitangent);
- vec3 vertexToCamera;
-
- // Set the tri vertex position to the intersection point on the tex tri plane
- // along the vector from the tri vertex to the camera.
- // Point of intersection p, from https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection#Algebraic_form:
- // d = ((p_0 - l_0) ⋅ n) / (l ⋅ n)
- // p = l_0 + l * d
- // where p_0 = point on tex tri plane
- // l_0 = point being projected
- // n = normal of tex tri plane
- // l = vector from vertex to camera
- vertexToCamera = cameraPos - f1;
- f1 += vertexToCamera * dot(t1 - f1, texNormal) / dot(vertexToCamera, texNormal);
-
- vertexToCamera = cameraPos - f2;
- f2 += vertexToCamera * dot(t2 - f2, texNormal) / dot(vertexToCamera, texNormal);
-
- vertexToCamera = cameraPos - f3;
- f3 += vertexToCamera * dot(t3 - f3, texNormal) / dot(vertexToCamera, texNormal);
-
- vec3 v4 = f1 - t1;
- vec3 v5 = f2 - t1;
- vec3 v6 = f3 - t1;
-
- vec3 v8 = cross(bitangent, texNormal);
- float d = 1.0f / dot(v8, tangent);
-
- float u1 = dot(v8, v4) * d;
- float u2 = dot(v8, v5) * d;
- float u3 = dot(v8, v6) * d;
-
- v8 = cross(tangent, texNormal);
- d = 1.0f / dot(v8, bitangent);
-
- float v1 = dot(v8, v4) * d;
- float v2 = dot(v8, v5) * d;
- float v3 = dot(v8, v6) * d;
-
- uv1 = vec2(u1, v1);
- uv2 = vec2(u2, v2);
- uv3 = vec2(u3, v3);
-}
\ No newline at end of file
diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/gpu/vert.glsl b/runelite-client/src/main/resources/net/runelite/client/plugins/gpu/vert.glsl
index ad8f5e19c69..db720937fed 100644
--- a/runelite-client/src/main/resources/net/runelite/client/plugins/gpu/vert.glsl
+++ b/runelite-client/src/main/resources/net/runelite/client/plugins/gpu/vert.glsl
@@ -22,9 +22,17 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-
#version 330
+//#define ZBUF_DEBUG
+//#define BIAS_DEBUG
+
+#include texture_config
+
+// smallest unit of the texture which can be moved per tick. textures are all
+// 128x128px - so this is equivalent to +1px
+#define TEXTURE_ANIM_UNIT (1.0f / 128.0f)
+
#define TILE_SIZE 128.f
#define FOG_SCENE_EDGE_MIN ((-expandedMapLoadingChunks * 8 + 1) * TILE_SIZE)
@@ -44,6 +52,7 @@ layout(std140) uniform uniforms {
float cameraZ;
};
+uniform mat4 worldProj;
uniform mat4 entityProj;
uniform ivec4 entityTint;
uniform float brightness;
@@ -52,14 +61,17 @@ uniform int fogDepth;
uniform int drawDistance;
uniform int expandedMapLoadingChunks;
uniform ivec3 base;
-
-out vec4 gVertex;
-out vec4 gColor;
-out float gHsl;
-out int gTextureId;
-out vec4 gTexPos;
-out float gFogAmount;
-out int gBias;
+uniform int tick;
+uniform vec2 textureAnimations[TEXTURE_COUNT];
+
+out vec4 fColor;
+noperspective centroid out float fHsl;
+flat out int fTextureId;
+out vec2 fUv;
+out float fFogAmount;
+#ifdef ZBUF_DEBUG
+out float fDepth;
+#endif
#include "hsl_to_rgb.glsl"
@@ -70,17 +82,32 @@ float fogFactorLinear(const float dist, const float start, const float end) {
void main() {
vec4 vert = vec4(vertf + base, 1);
float a = float(abhsl >> 24 & 0xff) / 255.f;
+ int bias = (abhsl >> 16) & 0xff;
vec3 hsl = vec3(abhsl >> 10 & 63, abhsl >> 7 & 7, abhsl & 127);
hsl += ((entityTint.xyz - hsl) * entityTint.w) / 128;
vec3 rgb = hslToRgb(hsl);
- gVertex = entityProj * vert;
- gColor = vec4(rgb, 1.f - a);
- gHsl = abhsl & 0xffff; // only used for texture lighting, which isn't affected by tint
-
- gTextureId = tex.x; // the texture id + 1
- gTexPos = entityProj * (trunc(vert) + vec4(tex.yzw, 0));
+ vec4 worldPos = entityProj * vert;
+ vec4 screenPos = worldProj * worldPos;
+#ifdef ZBUF_DEBUG
+ fDepth = screenPos.z / screenPos.w;
+#endif
+ screenPos.z += float(bias) / 128.0;
+ gl_Position = screenPos;
+#ifdef BIAS_DEBUG
+ fColor = vec4(clamp(bias, 0, 12) / 12.0, 0.0, 0.0, 1.0);
+#else
+ fColor = vec4(rgb, 1.f - a);
+#endif
+ fHsl = float(abhsl & 0xffff); // only used for texture lighting, which isn't affected by tint
+
+ fTextureId = tex.x; // the texture id + 1
+ fUv = vec2(float(tex.y) / 256.f, float(tex.z) / 256.f);
+ if (fTextureId > 0) {
+ vec2 textureAnim = textureAnimations[min(fTextureId - 1, TEXTURE_COUNT - 1)];
+ fUv += float(tick) * textureAnim * TEXTURE_ANIM_UNIT;
+ }
float fogWest = max(FOG_SCENE_EDGE_MIN, cameraX - drawDistance);
float fogEast = min(FOG_SCENE_EDGE_MAX, cameraX + drawDistance);
@@ -88,15 +115,13 @@ void main() {
float fogNorth = min(FOG_SCENE_EDGE_MAX, cameraZ + drawDistance);
// Calculate distance from the scene edge
- float xDist = min(gVertex.x - fogWest, fogEast - gVertex.x);
- float zDist = min(gVertex.z - fogSouth, fogNorth - gVertex.z);
+ float xDist = min(worldPos.x - fogWest, fogEast - worldPos.x);
+ float zDist = min(worldPos.z - fogSouth, fogNorth - worldPos.z);
float nearestEdgeDistance = min(xDist, zDist);
float secondNearestEdgeDistance = max(xDist, zDist);
float fogDistance =
nearestEdgeDistance - FOG_CORNER_ROUNDING * TILE_SIZE *
max(0.f, (nearestEdgeDistance + FOG_CORNER_ROUNDING_SQUARED) / (secondNearestEdgeDistance + FOG_CORNER_ROUNDING_SQUARED));
- gFogAmount = fogFactorLinear(fogDistance, 0, fogDepth * TILE_SIZE) * useFog;
-
- gBias = (abhsl >> 16) & 0xff;
+ fFogAmount = fogFactorLinear(fogDistance, 0.f, fogDepth * TILE_SIZE) * useFog;
}
diff --git a/runelite-jshell/pom.xml b/runelite-jshell/pom.xml
index 693fcf8b22a..aa4f7eda6e0 100644
--- a/runelite-jshell/pom.xml
+++ b/runelite-jshell/pom.xml
@@ -30,7 +30,7 @@
net.runelite
runelite-parent
- 1.12.3
+ 1.12.4
jshell
diff --git a/runelite-maven-plugin/pom.xml b/runelite-maven-plugin/pom.xml
index 9c39efcabe8..08d28b77f33 100644
--- a/runelite-maven-plugin/pom.xml
+++ b/runelite-maven-plugin/pom.xml
@@ -29,7 +29,7 @@
net.runelite
runelite-parent
- 1.12.3
+ 1.12.4
runelite-maven-plugin