mirror of
https://gitlab.com/2009scape/rt4-client.git
synced 2026-08-01 14:39:16 -06:00
Final commit
This commit is contained in:
parent
a7c7dea3c7
commit
d29dd6f1b7
10 changed files with 1070 additions and 100 deletions
|
|
@ -20,6 +20,10 @@ import static rt4.Player.plane;
|
|||
* @author ceikry
|
||||
*/
|
||||
public class API {
|
||||
public static final int TILE_FLAG_UNDER_ROOF = 0x4;
|
||||
private static final int DEFAULT_ROOF_VISIBILITY_GROUP_LIMIT = 2;
|
||||
private static RoofVisibilityHandler roofVisibilityHandler = null;
|
||||
|
||||
public static Runnable[] miniMenuCustomActions = new Runnable[10];
|
||||
public static int customMiniMenuIndex = 0;
|
||||
public static ArrayList<KeyAdapter> registeredKeyListeners = new ArrayList<>();
|
||||
|
|
@ -246,6 +250,104 @@ public class API {
|
|||
return client.gameState == 30;
|
||||
}
|
||||
|
||||
public static int[] GetMapFlagTile() {
|
||||
if (LoginManager.mapFlagX == 0) {
|
||||
return null;
|
||||
}
|
||||
return new int[]{LoginManager.mapFlagX, LoginManager.mapFlagZ};
|
||||
}
|
||||
|
||||
public static void SetRoofVisibilityHandler(RoofVisibilityHandler handler) {
|
||||
roofVisibilityHandler = handler;
|
||||
}
|
||||
|
||||
public static void ClearRoofVisibilityHandler(RoofVisibilityHandler handler) {
|
||||
if (roofVisibilityHandler == handler) {
|
||||
roofVisibilityHandler = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetRoofVisibilityGroupLimit() {
|
||||
if (roofVisibilityHandler == null) {
|
||||
return DEFAULT_ROOF_VISIBILITY_GROUP_LIMIT;
|
||||
}
|
||||
return Math.max(DEFAULT_ROOF_VISIBILITY_GROUP_LIMIT, roofVisibilityHandler.getGroupLimit());
|
||||
}
|
||||
|
||||
public static boolean IsRoofVisibilityActive() {
|
||||
return roofVisibilityHandler != null && roofVisibilityHandler.isActive();
|
||||
}
|
||||
|
||||
public static void DisableRoofVisibilityIfExpired() {
|
||||
if (roofVisibilityHandler != null) {
|
||||
roofVisibilityHandler.disableIfExpired();
|
||||
}
|
||||
}
|
||||
|
||||
public static void EnsureRoofVisibilityBuffers() {
|
||||
if (roofVisibilityHandler != null) {
|
||||
roofVisibilityHandler.ensureBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
public static void ApplyRoofVisibilityRequests() {
|
||||
if (roofVisibilityHandler != null) {
|
||||
roofVisibilityHandler.applyRequests();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean IsRoofVisibilityPicking() {
|
||||
return roofVisibilityHandler != null && roofVisibilityHandler.isPicking();
|
||||
}
|
||||
|
||||
public static int GetRoofVisibilityPickScreenX() {
|
||||
return roofVisibilityHandler == null ? 0 : roofVisibilityHandler.getPickScreenX();
|
||||
}
|
||||
|
||||
public static int GetRoofVisibilityPickScreenY() {
|
||||
return roofVisibilityHandler == null ? 0 : roofVisibilityHandler.getPickScreenY();
|
||||
}
|
||||
|
||||
public static void ReportRoofVisibilityTile(int sceneX, int sceneZ, int plane) {
|
||||
if (roofVisibilityHandler != null) {
|
||||
roofVisibilityHandler.reportTile(sceneX, sceneZ, plane);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean IsRoofVisibilityLocPickable(long key) {
|
||||
return roofVisibilityHandler != null && roofVisibilityHandler.isLocPickable(key);
|
||||
}
|
||||
|
||||
public static void ReportRoofVisibilityLoc(long key, int plane) {
|
||||
if (roofVisibilityHandler != null) {
|
||||
roofVisibilityHandler.reportLoc(key, plane);
|
||||
}
|
||||
}
|
||||
|
||||
public static void BeginRoofVisibilityGroup(int group) {
|
||||
if (roofVisibilityHandler != null) {
|
||||
roofVisibilityHandler.beginGroup(group);
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddRoofVisibilityGroupTile(int group, int plane, int sceneX, int sceneZ) {
|
||||
if (roofVisibilityHandler != null) {
|
||||
roofVisibilityHandler.addGroupTile(group, plane, sceneX, sceneZ);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetDestinationRoofTarget(int sceneX, int sceneZ) {
|
||||
if (roofVisibilityHandler != null) {
|
||||
roofVisibilityHandler.setDestinationTarget(sceneX, sceneZ);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ClearDestinationRoofTarget() {
|
||||
if (roofVisibilityHandler != null) {
|
||||
roofVisibilityHandler.clearDestinationTarget();
|
||||
}
|
||||
}
|
||||
|
||||
public static void StoreData(String key, Object value) {
|
||||
PluginRepository.pluginStorage.put(key, value);
|
||||
PluginRepository.pluginStorage.put("_keystoreDirty", true);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import org.openrs2.deob.annotation.OriginalArg;
|
|||
import org.openrs2.deob.annotation.OriginalClass;
|
||||
import org.openrs2.deob.annotation.OriginalMember;
|
||||
import org.openrs2.deob.annotation.Pc;
|
||||
import plugin.api.API;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
|
|
@ -972,7 +973,9 @@ public final class GlModel extends Model {
|
|||
local161 = MathUtils.sin[arg0];
|
||||
local163 = MathUtils.cos[arg0];
|
||||
}
|
||||
if (arg8 > 0L && RawModel.allowInput && local70 > 0) {
|
||||
@Pc(165) boolean roofVisibilityLocPick = API.IsRoofVisibilityLocPickable(arg8);
|
||||
@Pc(168) boolean miniMenuPick = arg8 > 0L;
|
||||
if ((miniMenuPick || roofVisibilityLocPick) && RawModel.allowInput && local70 > 0) {
|
||||
@Pc(187) int local187;
|
||||
@Pc(191) int local191;
|
||||
if (local84 > 0) {
|
||||
|
|
@ -1046,63 +1049,79 @@ public final class GlModel extends Model {
|
|||
}
|
||||
if (anInt3582 >= local187 && anInt3582 <= local191 && RawModel.anInt1053 >= local206 && RawModel.anInt1053 <= local210) {
|
||||
if (this.pickable) {
|
||||
Model.aLongArray11[MiniMenu.anInt7++] = arg8;
|
||||
} else {
|
||||
if (anIntArray468.length < this.anInt5296) {
|
||||
anIntArray468 = new int[this.anInt5296];
|
||||
anIntArray467 = new int[this.anInt5296];
|
||||
if (miniMenuPick) {
|
||||
Model.aLongArray11[MiniMenu.anInt7++] = arg8;
|
||||
}
|
||||
local362 = 0;
|
||||
label118:
|
||||
while (true) {
|
||||
if (local362 >= this.vertexCount) {
|
||||
local362 = 0;
|
||||
while (true) {
|
||||
if (local362 >= this.triangleCount) {
|
||||
break label118;
|
||||
if (roofVisibilityLocPick) {
|
||||
API.ReportRoofVisibilityLoc(arg8, arg9);
|
||||
}
|
||||
} else {
|
||||
if (this.vertexX == null || this.vertexY == null || this.vertexZ == null || this.anIntArray462 == null || this.aShortArray81 == null) {
|
||||
if (roofVisibilityLocPick) {
|
||||
API.ReportRoofVisibilityLoc(arg8, arg9);
|
||||
}
|
||||
} else {
|
||||
if (anIntArray468.length < this.anInt5296) {
|
||||
anIntArray468 = new int[this.anInt5296];
|
||||
anIntArray467 = new int[this.anInt5296];
|
||||
}
|
||||
local362 = 0;
|
||||
label118:
|
||||
while (true) {
|
||||
if (local362 >= this.vertexCount) {
|
||||
local362 = 0;
|
||||
while (true) {
|
||||
if (local362 >= this.triangleCount) {
|
||||
break label118;
|
||||
}
|
||||
@Pc(698) short local698 = this.aShortArray77[local362];
|
||||
@Pc(703) short local703 = this.aShortArray82[local362];
|
||||
@Pc(708) short local708 = this.aShortArray83[local362];
|
||||
if (this.method4118(anInt3582, RawModel.anInt1053, anIntArray467[local698], anIntArray467[local703], anIntArray467[local708], anIntArray468[local698], anIntArray468[local703], anIntArray468[local708])) {
|
||||
if (miniMenuPick) {
|
||||
Model.aLongArray11[MiniMenu.anInt7++] = arg8;
|
||||
}
|
||||
if (roofVisibilityLocPick) {
|
||||
API.ReportRoofVisibilityLoc(arg8, arg9);
|
||||
}
|
||||
break label118;
|
||||
}
|
||||
local362++;
|
||||
}
|
||||
@Pc(698) short local698 = this.aShortArray77[local362];
|
||||
@Pc(703) short local703 = this.aShortArray82[local362];
|
||||
@Pc(708) short local708 = this.aShortArray83[local362];
|
||||
if (this.method4118(anInt3582, RawModel.anInt1053, anIntArray467[local698], anIntArray467[local703], anIntArray467[local708], anIntArray468[local698], anIntArray468[local703], anIntArray468[local708])) {
|
||||
Model.aLongArray11[MiniMenu.anInt7++] = arg8;
|
||||
break label118;
|
||||
}
|
||||
local362++;
|
||||
}
|
||||
}
|
||||
local369 = this.vertexX[local362];
|
||||
local373 = this.vertexY[local362];
|
||||
local377 = this.vertexZ[local362];
|
||||
if (arg0 != 0) {
|
||||
local389 = local377 * local161 + local369 * local163 >> 16;
|
||||
local377 = local377 * local163 - local369 * local161 >> 16;
|
||||
local369 = this.vertexX[local362];
|
||||
local373 = this.vertexY[local362];
|
||||
local377 = this.vertexZ[local362];
|
||||
if (arg0 != 0) {
|
||||
local389 = local377 * local161 + local369 * local163 >> 16;
|
||||
local377 = local377 * local163 - local369 * local161 >> 16;
|
||||
local369 = local389;
|
||||
}
|
||||
local369 += arg5;
|
||||
local373 += arg6;
|
||||
local377 += arg7;
|
||||
local389 = local377 * arg3 + local369 * arg4 >> 16;
|
||||
local377 = local377 * arg4 - local369 * arg3 >> 16;
|
||||
local369 = local389;
|
||||
}
|
||||
local369 += arg5;
|
||||
local373 += arg6;
|
||||
local377 += arg7;
|
||||
local389 = local377 * arg3 + local369 * arg4 >> 16;
|
||||
local377 = local377 * arg4 - local369 * arg3 >> 16;
|
||||
local369 = local389;
|
||||
local389 = local373 * arg2 - local377 * arg1 >> 16;
|
||||
local377 = local373 * arg1 + local377 * arg2 >> 16;
|
||||
if (local377 < 50) {
|
||||
break;
|
||||
}
|
||||
local465 = (local369 << 9) / local377;
|
||||
local471 = (local389 << 9) / local377;
|
||||
@Pc(652) int local652 = this.anIntArray462[local362];
|
||||
@Pc(659) int local659 = this.anIntArray462[local362 + 1];
|
||||
for (@Pc(661) int local661 = local652; local661 < local659; local661++) {
|
||||
@Pc(671) int local671 = this.aShortArray81[local661] - 1;
|
||||
if (local671 == -1) {
|
||||
local389 = local373 * arg2 - local377 * arg1 >> 16;
|
||||
local377 = local373 * arg1 + local377 * arg2 >> 16;
|
||||
if (local377 < 50) {
|
||||
break;
|
||||
}
|
||||
anIntArray468[local671] = local465;
|
||||
anIntArray467[local671] = local471;
|
||||
local465 = (local369 << 9) / local377;
|
||||
local471 = (local389 << 9) / local377;
|
||||
@Pc(652) int local652 = this.anIntArray462[local362];
|
||||
@Pc(659) int local659 = this.anIntArray462[local362 + 1];
|
||||
for (@Pc(661) int local661 = local652; local661 < local659; local661++) {
|
||||
@Pc(671) int local671 = this.aShortArray81[local661] - 1;
|
||||
if (local671 == -1) {
|
||||
break;
|
||||
}
|
||||
anIntArray468[local671] = local465;
|
||||
anIntArray467[local671] = local471;
|
||||
}
|
||||
local362++;
|
||||
}
|
||||
local362++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -606,11 +606,17 @@ public class MiniMenu {
|
|||
}
|
||||
if (actionCode == WALK_HERE) {
|
||||
if (local36 == 0) {
|
||||
if (API.IsRoofVisibilityActive()) {
|
||||
API.ClearDestinationRoofTarget();
|
||||
}
|
||||
method3556(Player.plane, local15, local19);
|
||||
} else if (local36 == 1) {
|
||||
if (LoginManager.staffModLevel > 0 && Keyboard.pressedKeys[Keyboard.KEY_CTRL] && Keyboard.pressedKeys[Keyboard.KEY_SHIFT]) {
|
||||
Cheat.teleport(Camera.originX + local15, Camera.originZ + local19, Player.plane);
|
||||
} else if (PathFinder.findPath(PlayerList.self.movementQueueZ[0], 0, 0, true, 0, local15, 0, 0, 1, local19, PlayerList.self.movementQueueX[0])) {
|
||||
if (API.IsRoofVisibilityActive()) {
|
||||
API.SetDestinationRoofTarget(local15, local19);
|
||||
}
|
||||
Protocol.outboundBuffer.p1(InterfaceList.anInt5);
|
||||
Protocol.outboundBuffer.p1(anInt2878);
|
||||
Protocol.outboundBuffer.p2((int) Camera.yawTarget);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import com.jogamp.opengl.GL2;
|
|||
import org.openrs2.deob.annotation.OriginalArg;
|
||||
import org.openrs2.deob.annotation.OriginalMember;
|
||||
import org.openrs2.deob.annotation.Pc;
|
||||
import plugin.api.API;
|
||||
|
||||
public class SceneGraph {
|
||||
|
||||
|
|
@ -1744,7 +1745,7 @@ public class SceneGraph {
|
|||
}
|
||||
if (local153.plainTile == null) {
|
||||
if (local153.shapedTile != null) {
|
||||
method2762(local153.shapedTile, anInt2886, anInt3038, anInt5205, anInt2222, local18, local21, method187(0, local18, local21));
|
||||
method2762(local153.shapedTile, anInt2886, anInt3038, anInt5205, anInt2222, local18, local21, 0, method187(0, local18, local21));
|
||||
}
|
||||
} else
|
||||
method2610(local153.plainTile, 0, anInt2886, anInt3038, anInt5205, anInt2222, local18, local21, method187(0, local18, local21));
|
||||
|
|
@ -1776,10 +1777,10 @@ public class SceneGraph {
|
|||
if (local8.plainTile == null) {
|
||||
if (local8.shapedTile != null) {
|
||||
if (method187(local27, local18, local21)) {
|
||||
method2762(local8.shapedTile, anInt2886, anInt3038, anInt5205, anInt2222, local18, local21, true);
|
||||
method2762(local8.shapedTile, anInt2886, anInt3038, anInt5205, anInt2222, local18, local21, local27, true);
|
||||
} else {
|
||||
var24 = true;
|
||||
method2762(local8.shapedTile, anInt2886, anInt3038, anInt5205, anInt2222, local18, local21, false);
|
||||
method2762(local8.shapedTile, anInt2886, anInt3038, anInt5205, anInt2222, local18, local21, local27, false);
|
||||
}
|
||||
}
|
||||
} else if (method187(local27, local18, local21)) {
|
||||
|
|
@ -3915,6 +3916,9 @@ public class SceneGraph {
|
|||
MiniMenu.anInt1742 = arg6;
|
||||
MiniMenu.anInt2954 = arg7;
|
||||
}
|
||||
if (API.IsRoofVisibilityPicking() && method583(API.GetRoofVisibilityPickScreenX() + Rasteriser.centerX, API.GetRoofVisibilityPickScreenY() + Rasteriser.centerY, local315, local331, local299, local307, local323, local291)) {
|
||||
API.ReportRoofVisibilityTile(arg6, arg7, arg1);
|
||||
}
|
||||
if (!GlRenderer.enabled && !arg8) {
|
||||
Rasteriser.testX = local307 < 0 || local323 < 0 || local291 < 0 || local307 > Rasteriser.width || local323 > Rasteriser.width || local291 > Rasteriser.width;
|
||||
if (arg0.anInt4869 == -1) {
|
||||
|
|
@ -3938,6 +3942,9 @@ public class SceneGraph {
|
|||
MiniMenu.anInt1742 = arg6;
|
||||
MiniMenu.anInt2954 = arg7;
|
||||
}
|
||||
if (API.IsRoofVisibilityPicking() && method583(API.GetRoofVisibilityPickScreenX() + Rasteriser.centerX, API.GetRoofVisibilityPickScreenY() + Rasteriser.centerY, local283, local299, local331, local275, local291, local323)) {
|
||||
API.ReportRoofVisibilityTile(arg6, arg7, arg1);
|
||||
}
|
||||
if (GlRenderer.enabled || arg8) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -4225,7 +4232,7 @@ public class SceneGraph {
|
|||
}
|
||||
|
||||
@OriginalMember(owner = "client!lh", name = "a", descriptor = "(Lclient!fg;IIIIIIZ)V")
|
||||
public static void method2762(@OriginalArg(0) ShapedTile arg0, @OriginalArg(1) int arg1, @OriginalArg(2) int arg2, @OriginalArg(3) int arg3, @OriginalArg(4) int arg4, @OriginalArg(5) int arg5, @OriginalArg(6) int arg6, @OriginalArg(7) boolean arg7) {
|
||||
public static void method2762(@OriginalArg(0) ShapedTile arg0, @OriginalArg(1) int arg1, @OriginalArg(2) int arg2, @OriginalArg(3) int arg3, @OriginalArg(4) int arg4, @OriginalArg(5) int arg5, @OriginalArg(6) int arg6, int arg7, @OriginalArg(7) boolean arg8) {
|
||||
@Pc(3) int local3 = arg0.anIntArray168.length;
|
||||
@Pc(5) int local5;
|
||||
@Pc(15) int local15;
|
||||
|
|
@ -4268,7 +4275,10 @@ public class SceneGraph {
|
|||
MiniMenu.anInt1742 = arg5;
|
||||
MiniMenu.anInt2954 = arg6;
|
||||
}
|
||||
if (!GlRenderer.enabled && !arg7) {
|
||||
if (API.IsRoofVisibilityPicking() && method583(API.GetRoofVisibilityPickScreenX() + Rasteriser.centerX, API.GetRoofVisibilityPickScreenY() + Rasteriser.centerY, local156, local160, local164, local39, local148, local152)) {
|
||||
API.ReportRoofVisibilityTile(arg5, arg6, arg7);
|
||||
}
|
||||
if (!GlRenderer.enabled && !arg8) {
|
||||
Rasteriser.testX = local39 < 0 || local148 < 0 || local152 < 0 || local39 > Rasteriser.width || local148 > Rasteriser.width || local152 > Rasteriser.width;
|
||||
if (arg0.anIntArray161 == null || arg0.anIntArray161[local5] == -1) {
|
||||
if (arg0.anIntArray167[local5] != 12345678) {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import org.openrs2.deob.annotation.OriginalArg;
|
|||
import org.openrs2.deob.annotation.OriginalMember;
|
||||
import org.openrs2.deob.annotation.Pc;
|
||||
import plugin.PluginRepository;
|
||||
import plugin.api.API;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Calendar;
|
||||
|
|
@ -116,15 +117,15 @@ public final class ScriptRunner {
|
|||
@OriginalMember(owner = "client!vg", name = "c", descriptor = "Z")
|
||||
public static boolean aBoolean299 = false;
|
||||
@OriginalMember(owner = "client!lj", name = "z", descriptor = "[I")
|
||||
public static int[] anIntArray338 = new int[2];
|
||||
public static int[] anIntArray338 = new int[8];
|
||||
@OriginalMember(owner = "client!vl", name = "i", descriptor = "[I")
|
||||
public static int[] anIntArray518 = new int[2];
|
||||
public static int[] anIntArray518 = new int[8];
|
||||
@OriginalMember(owner = "client!tk", name = "K", descriptor = "[I")
|
||||
public static int[] anIntArray476 = new int[2];
|
||||
public static int[] anIntArray476 = new int[8];
|
||||
@OriginalMember(owner = "client!e", name = "xc", descriptor = "[I")
|
||||
public static int[] anIntArray134 = new int[2];
|
||||
public static int[] anIntArray134 = new int[8];
|
||||
@OriginalMember(owner = "client!ge", name = "k", descriptor = "[I")
|
||||
public static int[] anIntArray205 = new int[2];
|
||||
public static int[] anIntArray205 = new int[8];
|
||||
@OriginalMember(owner = "client!nm", name = "W", descriptor = "Lclient!na;")
|
||||
public static JagString url;
|
||||
@OriginalMember(owner = "client!bf", name = "B", descriptor = "I")
|
||||
|
|
@ -976,12 +977,16 @@ public final class ScriptRunner {
|
|||
method2608();
|
||||
} else {
|
||||
method960((byte) (anInt3325 - 4 & 0xFF));
|
||||
method3993(2);
|
||||
method3993(API.GetRoofVisibilityGroupLimit());
|
||||
}
|
||||
}
|
||||
|
||||
@OriginalMember(owner = "client!tc", name = "a", descriptor = "(B)I")
|
||||
public static int method4047() {
|
||||
return getBaseRoofMode();
|
||||
}
|
||||
|
||||
private static int getBaseRoofMode() {
|
||||
if (neverRemoveRoofs) {
|
||||
return 0;
|
||||
} else if (SceneGraph.allLevelsAreVisible()) {
|
||||
|
|
@ -991,6 +996,11 @@ public final class ScriptRunner {
|
|||
}
|
||||
}
|
||||
|
||||
public static boolean canUseSelectiveRoofHiding() {
|
||||
return getBaseRoofMode() == 2;
|
||||
}
|
||||
|
||||
|
||||
@OriginalMember(owner = "client!ok", name = "a", descriptor = "(IIB)Lclient!ce;")
|
||||
public static SecondaryLinkedList method3333(@OriginalArg(0) int arg0, @OriginalArg(1) int arg1) {
|
||||
@Pc(9) SecondaryLinkedList local9 = new SecondaryLinkedList();
|
||||
|
|
@ -1042,18 +1052,31 @@ public final class ScriptRunner {
|
|||
|
||||
@OriginalMember(owner = "client!uj", name = "a", descriptor = "(BZII[[[Lclient!bj;I)Z")
|
||||
public static boolean method4348(@OriginalArg(1) boolean arg0, @OriginalArg(2) int arg1, @OriginalArg(3) int arg2, @OriginalArg(4) Tile[][][] arg3, @OriginalArg(5) int arg4) {
|
||||
@Pc(14) byte local14 = arg0 ? 1 : (byte) (anInt3325 & 0xFF);
|
||||
if (local14 == aByteArrayArrayArray15[Player.plane][arg1][arg2]) {
|
||||
return method4348(arg0, arg1, arg2, arg3, arg4, Player.plane);
|
||||
}
|
||||
|
||||
|
||||
public static boolean hideRoofAt(int sceneX, int sceneZ, int group, int plane) {
|
||||
return method4348(false, sceneX, sceneZ, SceneGraph.tiles, group, plane);
|
||||
}
|
||||
|
||||
private static boolean method4348(boolean arg0, int arg1, int arg2, Tile[][][] arg3, int arg4, int plane) {
|
||||
if (plane < 0 || plane >= 3) {
|
||||
return false;
|
||||
} else if ((SceneGraph.renderFlags[Player.plane][arg1][arg2] & 0x4) == 0) {
|
||||
}
|
||||
@Pc(14) byte local14 = arg0 ? 1 : (byte) (anInt3325 & 0xFF);
|
||||
if (local14 == aByteArrayArrayArray15[plane][arg1][arg2]) {
|
||||
return false;
|
||||
} else if ((SceneGraph.renderFlags[plane][arg1][arg2] & API.TILE_FLAG_UNDER_ROOF) == 0) {
|
||||
return false;
|
||||
} else {
|
||||
API.BeginRoofVisibilityGroup(arg4);
|
||||
@Pc(47) int local47 = 0;
|
||||
@Pc(49) byte local49 = 0;
|
||||
PathFinder.queueX[0] = arg1;
|
||||
@Pc(69) int local69 = local49 + 1;
|
||||
PathFinder.queueZ[0] = arg2;
|
||||
aByteArrayArrayArray15[Player.plane][arg1][arg2] = local14;
|
||||
aByteArrayArrayArray15[plane][arg1][arg2] = local14;
|
||||
while (local47 != local69) {
|
||||
@Pc(94) int local94 = PathFinder.queueX[local47] >> 16 & 0xFF;
|
||||
@Pc(102) int local102 = PathFinder.queueX[local47] >> 24 & 0xFF;
|
||||
|
|
@ -1063,13 +1086,13 @@ public final class ScriptRunner {
|
|||
local47 = local47 + 1 & 0xFFF;
|
||||
@Pc(130) boolean local130 = false;
|
||||
@Pc(132) boolean local132 = false;
|
||||
if ((SceneGraph.renderFlags[Player.plane][local108][local122] & 0x4) == 0) {
|
||||
if ((SceneGraph.renderFlags[plane][local108][local122] & API.TILE_FLAG_UNDER_ROOF) == 0) {
|
||||
local130 = true;
|
||||
}
|
||||
@Pc(150) int local150;
|
||||
@Pc(191) int local191;
|
||||
label238:
|
||||
for (local150 = Player.plane + 1; local150 <= 3; local150++) {
|
||||
for (local150 = plane + 1; local150 <= 3; local150++) {
|
||||
if ((SceneGraph.renderFlags[local150][local108][local122] & 0x8) == 0) {
|
||||
@Pc(227) int local227;
|
||||
@Pc(358) int local358;
|
||||
|
|
@ -1124,8 +1147,8 @@ public final class ScriptRunner {
|
|||
}
|
||||
}
|
||||
if (local132) {
|
||||
if (SceneGraph.tileHeights[Player.plane + 1][local108][local122] > anIntArray205[arg4]) {
|
||||
anIntArray205[arg4] = SceneGraph.tileHeights[Player.plane + 1][local108][local122];
|
||||
if (SceneGraph.tileHeights[plane + 1][local108][local122] > anIntArray205[arg4]) {
|
||||
anIntArray205[arg4] = SceneGraph.tileHeights[plane + 1][local108][local122];
|
||||
}
|
||||
local150 = local108 << 7;
|
||||
if (local150 < anIntArray338[arg4]) {
|
||||
|
|
@ -1139,60 +1162,61 @@ public final class ScriptRunner {
|
|||
} else if (anIntArray134[arg4] < local191) {
|
||||
anIntArray134[arg4] = local191;
|
||||
}
|
||||
API.AddRoofVisibilityGroupTile(arg4, plane, local108, local122);
|
||||
}
|
||||
if (!local130) {
|
||||
if (local108 >= 1 && aByteArrayArrayArray15[Player.plane][local108 - 1][local122] != local14) {
|
||||
if (local108 >= 1 && aByteArrayArrayArray15[plane][local108 - 1][local122] != local14) {
|
||||
PathFinder.queueX[local69] = local108 - 1 | 0x120000 | 0xD3000000;
|
||||
PathFinder.queueZ[local69] = local122 | 0x130000;
|
||||
local69 = local69 + 1 & 0xFFF;
|
||||
aByteArrayArrayArray15[Player.plane][local108 - 1][local122] = local14;
|
||||
aByteArrayArrayArray15[plane][local108 - 1][local122] = local14;
|
||||
}
|
||||
local122++;
|
||||
if (local122 < 104) {
|
||||
if (local108 - 1 >= 0 && local14 != aByteArrayArrayArray15[Player.plane][local108 - 1][local122] && (SceneGraph.renderFlags[Player.plane][local108][local122] & 0x4) == 0 && (SceneGraph.renderFlags[Player.plane][local108 - 1][local122 - 1] & 0x4) == 0) {
|
||||
if (local108 - 1 >= 0 && local14 != aByteArrayArrayArray15[plane][local108 - 1][local122] && (SceneGraph.renderFlags[plane][local108][local122] & API.TILE_FLAG_UNDER_ROOF) == 0 && (SceneGraph.renderFlags[plane][local108 - 1][local122 - 1] & API.TILE_FLAG_UNDER_ROOF) == 0) {
|
||||
PathFinder.queueX[local69] = 0x52000000 | 0x120000 | local108 - 1;
|
||||
PathFinder.queueZ[local69] = local122 | 0x130000;
|
||||
aByteArrayArrayArray15[Player.plane][local108 - 1][local122] = local14;
|
||||
aByteArrayArrayArray15[plane][local108 - 1][local122] = local14;
|
||||
local69 = local69 + 1 & 0xFFF;
|
||||
}
|
||||
if (local14 != aByteArrayArrayArray15[Player.plane][local108][local122]) {
|
||||
if (local14 != aByteArrayArrayArray15[plane][local108][local122]) {
|
||||
PathFinder.queueX[local69] = local108 | 0x13000000 | 0x520000;
|
||||
PathFinder.queueZ[local69] = local122 | 0x530000;
|
||||
local69 = local69 + 1 & 0xFFF;
|
||||
aByteArrayArrayArray15[Player.plane][local108][local122] = local14;
|
||||
aByteArrayArrayArray15[plane][local108][local122] = local14;
|
||||
}
|
||||
if (local108 + 1 < 104 && aByteArrayArrayArray15[Player.plane][local108 + 1][local122] != local14 && (SceneGraph.renderFlags[Player.plane][local108][local122] & 0x4) == 0 && (SceneGraph.renderFlags[Player.plane][local108 + 1][local122 - 1] & 0x4) == 0) {
|
||||
if (local108 + 1 < 104 && aByteArrayArrayArray15[plane][local108 + 1][local122] != local14 && (SceneGraph.renderFlags[plane][local108][local122] & API.TILE_FLAG_UNDER_ROOF) == 0 && (SceneGraph.renderFlags[plane][local108 + 1][local122 - 1] & API.TILE_FLAG_UNDER_ROOF) == 0) {
|
||||
PathFinder.queueX[local69] = 0x92000000 | 0x520000 | local108 + 1;
|
||||
PathFinder.queueZ[local69] = local122 | 0x530000;
|
||||
aByteArrayArrayArray15[Player.plane][local108 + 1][local122] = local14;
|
||||
aByteArrayArrayArray15[plane][local108 + 1][local122] = local14;
|
||||
local69 = local69 + 1 & 0xFFF;
|
||||
}
|
||||
}
|
||||
local122--;
|
||||
if (local108 + 1 < 104 && local14 != aByteArrayArrayArray15[Player.plane][local108 + 1][local122]) {
|
||||
if (local108 + 1 < 104 && local14 != aByteArrayArrayArray15[plane][local108 + 1][local122]) {
|
||||
PathFinder.queueX[local69] = local108 + 1 | 0x920000 | 0x53000000;
|
||||
PathFinder.queueZ[local69] = local122 | 0x930000;
|
||||
aByteArrayArrayArray15[Player.plane][local108 + 1][local122] = local14;
|
||||
aByteArrayArrayArray15[plane][local108 + 1][local122] = local14;
|
||||
local69 = local69 + 1 & 0xFFF;
|
||||
}
|
||||
local122--;
|
||||
if (local122 >= 0) {
|
||||
if (local108 - 1 >= 0 && aByteArrayArrayArray15[Player.plane][local108 - 1][local122] != local14 && (SceneGraph.renderFlags[Player.plane][local108][local122] & 0x4) == 0 && (SceneGraph.renderFlags[Player.plane][local108 - 1][local122 + 1] & 0x4) == 0) {
|
||||
if (local108 - 1 >= 0 && aByteArrayArrayArray15[plane][local108 - 1][local122] != local14 && (SceneGraph.renderFlags[plane][local108][local122] & API.TILE_FLAG_UNDER_ROOF) == 0 && (SceneGraph.renderFlags[plane][local108 - 1][local122 + 1] & API.TILE_FLAG_UNDER_ROOF) == 0) {
|
||||
PathFinder.queueX[local69] = local108 - 1 | 0xD20000 | 0x12000000;
|
||||
PathFinder.queueZ[local69] = local122 | 0xD30000;
|
||||
aByteArrayArrayArray15[Player.plane][local108 - 1][local122] = local14;
|
||||
aByteArrayArrayArray15[plane][local108 - 1][local122] = local14;
|
||||
local69 = local69 + 1 & 0xFFF;
|
||||
}
|
||||
if (local14 != aByteArrayArrayArray15[Player.plane][local108][local122]) {
|
||||
if (local14 != aByteArrayArrayArray15[plane][local108][local122]) {
|
||||
PathFinder.queueX[local69] = local108 | 0xD20000 | 0x93000000;
|
||||
PathFinder.queueZ[local69] = local122 | 0xD30000;
|
||||
local69 = local69 + 1 & 0xFFF;
|
||||
aByteArrayArrayArray15[Player.plane][local108][local122] = local14;
|
||||
aByteArrayArrayArray15[plane][local108][local122] = local14;
|
||||
}
|
||||
if (local108 + 1 < 104 && aByteArrayArrayArray15[Player.plane][local108 + 1][local122] != local14 && (SceneGraph.renderFlags[Player.plane][local108][local122] & 0x4) == 0 && (SceneGraph.renderFlags[Player.plane][local108 + 1][local122 + 1] & 0x4) == 0) {
|
||||
if (local108 + 1 < 104 && aByteArrayArrayArray15[plane][local108 + 1][local122] != local14 && (SceneGraph.renderFlags[plane][local108][local122] & API.TILE_FLAG_UNDER_ROOF) == 0 && (SceneGraph.renderFlags[plane][local108 + 1][local122 + 1] & API.TILE_FLAG_UNDER_ROOF) == 0) {
|
||||
PathFinder.queueX[local69] = local108 + 1 | 0xD2000000 | 0x920000;
|
||||
PathFinder.queueZ[local69] = local122 | 0x930000;
|
||||
aByteArrayArrayArray15[Player.plane][local108 + 1][local122] = local14;
|
||||
aByteArrayArrayArray15[plane][local108 + 1][local122] = local14;
|
||||
local69 = local69 + 1 & 0xFFF;
|
||||
}
|
||||
}
|
||||
|
|
@ -1316,9 +1340,12 @@ public final class ScriptRunner {
|
|||
|
||||
@OriginalMember(owner = "client!uh", name = "f", descriptor = "(I)V")
|
||||
public static void method4302() {
|
||||
API.DisableRoofVisibilityIfExpired();
|
||||
if (method4047() != 2) {
|
||||
return;
|
||||
}
|
||||
API.EnsureRoofVisibilityBuffers();
|
||||
boolean roofVisibilityActive = API.IsRoofVisibilityActive();
|
||||
@Pc(27) byte local27 = (byte) (anInt3325 - 4 & 0xFF);
|
||||
@Pc(31) int local31 = anInt3325 % 104;
|
||||
@Pc(33) int local33;
|
||||
|
|
@ -1331,7 +1358,7 @@ public final class ScriptRunner {
|
|||
if (Player.plane == 3) {
|
||||
return;
|
||||
}
|
||||
for (local33 = 0; local33 < 2; local33++) {
|
||||
for (local33 = 0; local33 < anIntArray205.length; local33++) {
|
||||
anIntArray205[local33] = -1000000;
|
||||
anIntArray338[local33] = 1000000;
|
||||
anIntArray518[local33] = 0;
|
||||
|
|
@ -1340,14 +1367,17 @@ public final class ScriptRunner {
|
|||
}
|
||||
if (Camera.cameraType != 1) {
|
||||
local33 = SceneGraph.getTileHeight(Player.plane, Camera.renderX, Camera.renderZ);
|
||||
if (local33 - Camera.anInt40 < 800 && (SceneGraph.renderFlags[Player.plane][Camera.renderX >> 7][Camera.renderZ >> 7] & 0x4) != 0) {
|
||||
if (local33 - Camera.anInt40 < 800 && (SceneGraph.renderFlags[Player.plane][Camera.renderX >> 7][Camera.renderZ >> 7] & API.TILE_FLAG_UNDER_ROOF) != 0) {
|
||||
method4348(false, Camera.renderX >> 7, Camera.renderZ >> 7, SceneGraph.tiles, 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if ((SceneGraph.renderFlags[Player.plane][PlayerList.self.xFine >> 7][PlayerList.self.zFine >> 7] & 0x4) != 0) {
|
||||
if ((SceneGraph.renderFlags[Player.plane][PlayerList.self.xFine >> 7][PlayerList.self.zFine >> 7] & API.TILE_FLAG_UNDER_ROOF) != 0) {
|
||||
method4348(false, PlayerList.self.xFine >> 7, PlayerList.self.zFine >> 7, SceneGraph.tiles, 0);
|
||||
}
|
||||
if (roofVisibilityActive) {
|
||||
API.ApplyRoofVisibilityRequests();
|
||||
}
|
||||
if (Camera.cameraPitch >= 310) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -1378,7 +1408,7 @@ public final class ScriptRunner {
|
|||
} else if (local40 > local135) {
|
||||
local40--;
|
||||
}
|
||||
if ((SceneGraph.renderFlags[Player.plane][local33][local40] & 0x4) != 0) {
|
||||
if ((SceneGraph.renderFlags[Player.plane][local33][local40] & API.TILE_FLAG_UNDER_ROOF) != 0) {
|
||||
method4348(false, local33, local40, SceneGraph.tiles, 1);
|
||||
break;
|
||||
}
|
||||
|
|
@ -1390,7 +1420,7 @@ public final class ScriptRunner {
|
|||
local33--;
|
||||
}
|
||||
local186 -= 65536;
|
||||
if ((SceneGraph.renderFlags[Player.plane][local33][local40] & 0x4) != 0) {
|
||||
if ((SceneGraph.renderFlags[Player.plane][local33][local40] & API.TILE_FLAG_UNDER_ROOF) != 0) {
|
||||
method4348(false, local33, local40, SceneGraph.tiles, 1);
|
||||
break;
|
||||
}
|
||||
|
|
@ -1406,7 +1436,7 @@ public final class ScriptRunner {
|
|||
} else if (local33 > local162) {
|
||||
local33--;
|
||||
}
|
||||
if ((SceneGraph.renderFlags[Player.plane][local33][local40] & 0x4) != 0) {
|
||||
if ((SceneGraph.renderFlags[Player.plane][local33][local40] & API.TILE_FLAG_UNDER_ROOF) != 0) {
|
||||
method4348(false, local33, local40, SceneGraph.tiles, 1);
|
||||
break;
|
||||
}
|
||||
|
|
@ -1418,7 +1448,7 @@ public final class ScriptRunner {
|
|||
local40--;
|
||||
}
|
||||
local186 -= 65536;
|
||||
if ((SceneGraph.renderFlags[Player.plane][local33][local40] & 0x4) != 0) {
|
||||
if ((SceneGraph.renderFlags[Player.plane][local33][local40] & API.TILE_FLAG_UNDER_ROOF) != 0) {
|
||||
method4348(false, local33, local40, SceneGraph.tiles, 1);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import org.openrs2.deob.annotation.OriginalArg;
|
|||
import org.openrs2.deob.annotation.OriginalClass;
|
||||
import org.openrs2.deob.annotation.OriginalMember;
|
||||
import org.openrs2.deob.annotation.Pc;
|
||||
import plugin.api.API;
|
||||
|
||||
@OriginalClass("client!w")
|
||||
public final class SoftwareModel extends Model {
|
||||
|
|
@ -833,7 +834,9 @@ public final class SoftwareModel extends Model {
|
|||
@Pc(223) int x;
|
||||
@Pc(208) int y;
|
||||
@Pc(227) int z;
|
||||
if (key > 0L && RawModel.allowInput && d > 0) {
|
||||
@Pc(229) boolean roofVisibilityLocPick = API.IsRoofVisibilityLocPickable(key);
|
||||
@Pc(232) boolean miniMenuPick = key > 0L;
|
||||
if ((miniMenuPick || roofVisibilityLocPick) && RawModel.allowInput && d > 0) {
|
||||
if (e > 0) {
|
||||
v = maxScreenX / c;
|
||||
y = minScreenX / d;
|
||||
|
|
@ -893,7 +896,12 @@ public final class SoftwareModel extends Model {
|
|||
}
|
||||
if (GlModel.anInt3582 >= v && GlModel.anInt3582 <= y && RawModel.anInt1053 >= x && RawModel.anInt1053 <= z) {
|
||||
if (this.pickable) {
|
||||
Model.aLongArray11[MiniMenu.anInt7++] = key;
|
||||
if (miniMenuPick) {
|
||||
Model.aLongArray11[MiniMenu.anInt7++] = key;
|
||||
}
|
||||
if (roofVisibilityLocPick) {
|
||||
API.ReportRoofVisibilityLoc(key, arg9);
|
||||
}
|
||||
} else {
|
||||
local190 = true;
|
||||
}
|
||||
|
|
@ -933,7 +941,7 @@ public final class SoftwareModel extends Model {
|
|||
}
|
||||
}
|
||||
try {
|
||||
this.draw(project1, local190, key, b - d, c - d + 2, arg10);
|
||||
this.draw(project1, local190, key, b - d, c - d + 2, arg9, arg10);
|
||||
} catch (@Pc(713) Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
|
@ -1148,7 +1156,7 @@ public final class SoftwareModel extends Model {
|
|||
projectSceneZ[local52] = local71;
|
||||
}
|
||||
}
|
||||
this.draw(false, arg6 >= 0L, arg6, this.aShort35, this.aShort35 << 1, null);
|
||||
this.draw(false, arg6 >= 0L || API.IsRoofVisibilityLocPickable(arg6), arg6, this.aShort35, this.aShort35 << 1, Player.plane, null);
|
||||
} catch (@Pc(240) RuntimeException local240) {
|
||||
}
|
||||
}
|
||||
|
|
@ -1583,7 +1591,7 @@ public final class SoftwareModel extends Model {
|
|||
}
|
||||
|
||||
@OriginalMember(owner = "client!w", name = "a", descriptor = "(ZZJIILclient!ga;)V")
|
||||
private void draw(@OriginalArg(0) boolean arg0, @OriginalArg(1) boolean arg1, @OriginalArg(2) long arg2, @OriginalArg(3) int arg3, @OriginalArg(4) int arg4, @OriginalArg(5) ParticleSystem arg5) {
|
||||
private void draw(@OriginalArg(0) boolean arg0, @OriginalArg(1) boolean arg1, @OriginalArg(2) long arg2, @OriginalArg(3) int arg3, @OriginalArg(4) int arg4, int roofHidePlane, @OriginalArg(5) ParticleSystem arg5) {
|
||||
if (arg4 >= 1600) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -1659,7 +1667,12 @@ public final class SoftwareModel extends Model {
|
|||
}
|
||||
} else {
|
||||
if (arg1 && this.pointWithinTriangle(GlModel.anInt3582 + Rasteriser.centerX, RawModel.anInt1053 + Rasteriser.centerY, vertexScreenY[local51], vertexScreenY[local56], vertexScreenY[pri], local65, local69, local73)) {
|
||||
Model.aLongArray11[MiniMenu.anInt7++] = arg2;
|
||||
if (arg2 >= 0L) {
|
||||
Model.aLongArray11[MiniMenu.anInt7++] = arg2;
|
||||
}
|
||||
if (API.IsRoofVisibilityLocPickable(arg2)) {
|
||||
API.ReportRoofVisibilityLoc(arg2, roofHidePlane);
|
||||
}
|
||||
arg1 = false;
|
||||
}
|
||||
if ((local65 - local69) * (vertexScreenY[pri] - vertexScreenY[local56]) - (vertexScreenY[local51] - vertexScreenY[local56]) * (local73 - local69) > 0) {
|
||||
|
|
@ -1946,7 +1959,7 @@ public final class SoftwareModel extends Model {
|
|||
projectSceneZ[local52] = local71;
|
||||
}
|
||||
}
|
||||
this.draw(false, false, 0L, this.aShort35, this.aShort35 << 1, null);
|
||||
this.draw(false, false, 0L, this.aShort35, this.aShort35 << 1, Player.plane, null);
|
||||
} catch (@Pc(234) RuntimeException local234) {
|
||||
}
|
||||
}
|
||||
|
|
|
|||
33
client/src/main/kotlin/plugin/api/RoofVisibilityHandler.kt
Normal file
33
client/src/main/kotlin/plugin/api/RoofVisibilityHandler.kt
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
package plugin.api
|
||||
|
||||
interface RoofVisibilityHandler {
|
||||
fun getGroupLimit(): Int
|
||||
|
||||
fun isActive(): Boolean
|
||||
|
||||
fun disableIfExpired()
|
||||
|
||||
fun ensureBuffers()
|
||||
|
||||
fun applyRequests()
|
||||
|
||||
fun isPicking(): Boolean
|
||||
|
||||
fun getPickScreenX(): Int
|
||||
|
||||
fun getPickScreenY(): Int
|
||||
|
||||
fun reportTile(sceneX: Int, sceneZ: Int, plane: Int)
|
||||
|
||||
fun isLocPickable(key: Long): Boolean
|
||||
|
||||
fun reportLoc(key: Long, plane: Int)
|
||||
|
||||
fun beginGroup(group: Int)
|
||||
|
||||
fun addGroupTile(group: Int, plane: Int, sceneX: Int, sceneZ: Int)
|
||||
|
||||
fun setDestinationTarget(sceneX: Int, sceneZ: Int)
|
||||
|
||||
fun clearDestinationTarget()
|
||||
}
|
||||
703
plugin-playground/src/main/kotlin/SmartRoofs/RoofHider.kt
Normal file
703
plugin-playground/src/main/kotlin/SmartRoofs/RoofHider.kt
Normal file
|
|
@ -0,0 +1,703 @@
|
|||
package SmartRoofs
|
||||
|
||||
import plugin.api.API
|
||||
import plugin.api.MiniMenuAction
|
||||
import plugin.api.MiniMenuEntry
|
||||
import plugin.api.RoofVisibilityHandler
|
||||
import rt4.Camera
|
||||
import rt4.Cs1ScriptRunner
|
||||
import rt4.LocType
|
||||
import rt4.MathUtils
|
||||
import rt4.Player
|
||||
import rt4.PlayerList
|
||||
import rt4.SceneGraph
|
||||
import rt4.ScriptRunner
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
object RoofHider {
|
||||
private const val TILE_FLAG_UNDER_ROOF = API.TILE_FLAG_UNDER_ROOF
|
||||
private const val SMART_ROOFS_ACTIVE_GRACE_MS = 750L
|
||||
|
||||
private const val MAP_FLAG_ROOF_GROUP = 2
|
||||
|
||||
private const val HOVER_GROUP_START = 3
|
||||
private const val HOVER_TARGET_LIMIT = 8
|
||||
private const val HOVER_HOLD_MS = 125L
|
||||
private const val HOVER_PRIMARY_HIT_DISTANCE = 64
|
||||
private const val HOVER_BUILDING_FOOTPRINT_PRIMARY_HIT_DISTANCE = 12
|
||||
private const val HOVER_UPPER_PLANE_TILE_SEARCH_RADIUS = 2
|
||||
private const val HOVER_BUILDING_FOOTPRINT_X_PADDING = 2
|
||||
private const val HOVER_BUILDING_FOOTPRINT_TOP_PADDING = 64
|
||||
private const val HOVER_BUILDING_FOOTPRINT_BOTTOM_PADDING = 4
|
||||
private const val HOVER_OUTSIDE_GROUND_HIT_MS = 50L
|
||||
|
||||
private const val DESTINATION_TARGET_GROUP = HOVER_GROUP_START + HOVER_TARGET_LIMIT
|
||||
const val SELECTIVE_ROOF_GROUP_COUNT = DESTINATION_TARGET_GROUP + 1
|
||||
private const val DESTINATION_HOLD_MS = 20000L
|
||||
private const val DESTINATION_REACHED_DISTANCE = 1
|
||||
|
||||
@JvmField
|
||||
val HANDLER: RoofVisibilityHandler = object : RoofVisibilityHandler {
|
||||
override fun getGroupLimit(): Int = SELECTIVE_ROOF_GROUP_COUNT
|
||||
|
||||
override fun isActive(): Boolean = isSmartRoofsActive()
|
||||
|
||||
override fun disableIfExpired() = disableSmartRoofsIfExpired()
|
||||
|
||||
override fun ensureBuffers() = ensureSelectiveRoofBuffers()
|
||||
|
||||
override fun applyRequests() {
|
||||
hideMapFlagRoof()
|
||||
hideHoverTargets()
|
||||
hideDestinationTarget()
|
||||
}
|
||||
|
||||
override fun isPicking(): Boolean = isHoverPicking()
|
||||
|
||||
override fun getPickScreenX(): Int = getHoverPickScreenX()
|
||||
|
||||
override fun getPickScreenY(): Int = getHoverPickScreenY()
|
||||
|
||||
override fun reportTile(sceneX: Int, sceneZ: Int, plane: Int) {
|
||||
setHoverTile(sceneX, sceneZ, plane)
|
||||
}
|
||||
|
||||
override fun isLocPickable(key: Long): Boolean = isHoverLocPickable(key)
|
||||
|
||||
override fun reportLoc(key: Long, plane: Int) {
|
||||
setHoverLoc(key, plane)
|
||||
}
|
||||
|
||||
override fun beginGroup(group: Int) = beginBuildingFootprint(group)
|
||||
|
||||
override fun addGroupTile(group: Int, plane: Int, sceneX: Int, sceneZ: Int) {
|
||||
addBuildingFootprintTile(group, plane, sceneX, sceneZ)
|
||||
}
|
||||
|
||||
override fun setDestinationTarget(sceneX: Int, sceneZ: Int) {
|
||||
this@RoofHider.setDestinationTarget(sceneX, sceneZ)
|
||||
}
|
||||
|
||||
override fun clearDestinationTarget() = this@RoofHider.clearDestinationTarget()
|
||||
|
||||
}
|
||||
|
||||
private var smartRoofsEnabled = false
|
||||
private var smartRoofsActiveUntil = 0L
|
||||
private var smartRoofsWasActive = false
|
||||
|
||||
private var mapFlagRoofX = -1
|
||||
private var mapFlagRoofZ = -1
|
||||
private var mapFlagRoofRadius = 0
|
||||
|
||||
private var hoverPickActive = false
|
||||
private var hoverPickScreenX = 0
|
||||
private var hoverPickScreenY = 0
|
||||
private val hoverTargetX = IntArray(HOVER_TARGET_LIMIT) { -1 }
|
||||
private val hoverTargetZ = IntArray(HOVER_TARGET_LIMIT) { -1 }
|
||||
private val hoverTargetPlane = IntArray(HOVER_TARGET_LIMIT) { -1 }
|
||||
private val hoverPrimaryHitX = IntArray(HOVER_TARGET_LIMIT) { Int.MIN_VALUE }
|
||||
private val hoverPrimaryHitY = IntArray(HOVER_TARGET_LIMIT) { Int.MIN_VALUE }
|
||||
private val hoverTargetUntil = LongArray(HOVER_TARGET_LIMIT)
|
||||
private val buildingFootprintMinX = IntArray(HOVER_TARGET_LIMIT) { Int.MAX_VALUE }
|
||||
private val buildingFootprintMaxX = IntArray(HOVER_TARGET_LIMIT) { Int.MIN_VALUE }
|
||||
private val buildingFootprintMinY = IntArray(HOVER_TARGET_LIMIT) { Int.MAX_VALUE }
|
||||
private val buildingFootprintMaxY = IntArray(HOVER_TARGET_LIMIT) { Int.MIN_VALUE }
|
||||
private val buildingFootprintTiles = Array(HOVER_TARGET_LIMIT) { Array(104) { BooleanArray(104) } }
|
||||
private var lastHoverTileX = -1
|
||||
private var lastHoverTileZ = -1
|
||||
private var lastHoverTilePlane = -1
|
||||
private var lastHoverTileValid = false
|
||||
private var lastHoverTileAt = 0L
|
||||
private var lastHoverHitAt = 0L
|
||||
|
||||
private var destinationTargetX = -1
|
||||
private var destinationTargetZ = -1
|
||||
private var destinationTargetUntil = 0L
|
||||
|
||||
fun isSmartRoofsActive(): Boolean {
|
||||
return smartRoofsEnabled && isSmartRoofsActive(System.currentTimeMillis()) && ScriptRunner.canUseSelectiveRoofHiding()
|
||||
}
|
||||
|
||||
private fun isSmartRoofsActive(now: Long): Boolean {
|
||||
return now <= smartRoofsActiveUntil
|
||||
}
|
||||
|
||||
private fun updateSmartRoofsPulse(now: Long) {
|
||||
smartRoofsActiveUntil = now + SMART_ROOFS_ACTIVE_GRACE_MS
|
||||
smartRoofsWasActive = true
|
||||
}
|
||||
|
||||
private fun disableSmartRoofsIfExpired() {
|
||||
val now = System.currentTimeMillis()
|
||||
if (!smartRoofsWasActive || isSmartRoofsActive(now)) {
|
||||
return
|
||||
}
|
||||
clearSmartRoofsState()
|
||||
smartRoofsWasActive = false
|
||||
ScriptRunner.method2218()
|
||||
}
|
||||
|
||||
private fun clearSmartRoofsState() {
|
||||
clearMapFlagRoof()
|
||||
clearHoverRequest()
|
||||
clearDestinationTarget()
|
||||
smartRoofsEnabled = false
|
||||
}
|
||||
|
||||
fun setSmartRoofsEnabled(enabled: Boolean) {
|
||||
if (!enabled) {
|
||||
clearSmartRoofsState()
|
||||
return
|
||||
}
|
||||
smartRoofsEnabled = true
|
||||
}
|
||||
|
||||
fun updateSmartRoofs() {
|
||||
if (!smartRoofsEnabled) {
|
||||
clearSmartRoofsState()
|
||||
return
|
||||
}
|
||||
val now = System.currentTimeMillis()
|
||||
val wasActive = isSmartRoofsActive(now)
|
||||
updateSmartRoofsPulse(now)
|
||||
if (!ScriptRunner.canUseSelectiveRoofHiding()) {
|
||||
clearSmartRoofsState()
|
||||
return
|
||||
}
|
||||
val rebuild = !wasActive ||
|
||||
ScriptRunner.method4047() != 2 ||
|
||||
ScriptRunner.aByteArrayArrayArray15 == null ||
|
||||
ScriptRunner.anIntArray205.size < SELECTIVE_ROOF_GROUP_COUNT
|
||||
if (rebuild) {
|
||||
ScriptRunner.method2218()
|
||||
} else {
|
||||
ensureSelectiveRoofBuffers()
|
||||
}
|
||||
}
|
||||
|
||||
private fun ensureSelectiveRoofBuffers() {
|
||||
if (ScriptRunner.aByteArrayArrayArray15 == null) {
|
||||
ScriptRunner.method960(((ScriptRunner.anInt3325 - 4) and 0xFF).toByte())
|
||||
}
|
||||
if (ScriptRunner.anIntArray205.size < SELECTIVE_ROOF_GROUP_COUNT) {
|
||||
ScriptRunner.method3993(SELECTIVE_ROOF_GROUP_COUNT)
|
||||
}
|
||||
}
|
||||
|
||||
fun setMapFlagRoof(sceneX: Int, sceneZ: Int, radius: Int) {
|
||||
if (!isSmartRoofsActive()) {
|
||||
clearMapFlagRoof()
|
||||
return
|
||||
}
|
||||
if (!isInSceneBounds(sceneX, sceneZ)) {
|
||||
clearMapFlagRoof()
|
||||
return
|
||||
}
|
||||
mapFlagRoofX = sceneX
|
||||
mapFlagRoofZ = sceneZ
|
||||
mapFlagRoofRadius = radius.coerceIn(0, 8)
|
||||
}
|
||||
|
||||
fun clearMapFlagRoof() {
|
||||
mapFlagRoofX = -1
|
||||
mapFlagRoofZ = -1
|
||||
mapFlagRoofRadius = 0
|
||||
}
|
||||
|
||||
private fun hideMapFlagRoof() {
|
||||
hideRoofFromSeedTile(mapFlagRoofX, mapFlagRoofZ, mapFlagRoofRadius, MAP_FLAG_ROOF_GROUP, Player.plane)
|
||||
}
|
||||
|
||||
private fun hideRoofFromSeedTile(sceneX: Int, sceneZ: Int, radius: Int, group: Int, plane: Int): Boolean {
|
||||
if (sceneX == -1 || !isRoofHidePlane(plane) || ScriptRunner.anIntArray205.size <= group) {
|
||||
return false
|
||||
}
|
||||
for (currentRadius in 0..radius) {
|
||||
for (dx in -currentRadius..currentRadius) {
|
||||
for (dz in -currentRadius..currentRadius) {
|
||||
if (abs(dx) != currentRadius && abs(dz) != currentRadius) {
|
||||
continue
|
||||
}
|
||||
if (tryHideRoofFromTile(sceneX + dx, sceneZ + dz, group, plane)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun tryHideRoofFromTile(sceneX: Int, sceneZ: Int, group: Int, plane: Int): Boolean {
|
||||
if (!isHideableRoofTile(sceneX, sceneZ, plane)) {
|
||||
return false
|
||||
}
|
||||
val masks = ScriptRunner.aByteArrayArrayArray15 ?: return false
|
||||
val currentRoofMask = (ScriptRunner.anInt3325 and 0xFF).toByte()
|
||||
if (masks[plane][sceneX][sceneZ] == currentRoofMask) {
|
||||
return true
|
||||
}
|
||||
return ScriptRunner.hideRoofAt(sceneX, sceneZ, group, plane)
|
||||
}
|
||||
|
||||
fun updateHoverPick(entries: Array<out MiniMenuEntry>?) {
|
||||
if (!isSmartRoofsActive()) {
|
||||
clearHoverRequest()
|
||||
return
|
||||
}
|
||||
hoverPickActive = false
|
||||
if (entries == null) {
|
||||
clearExpiredHoverTargets(System.currentTimeMillis())
|
||||
return
|
||||
}
|
||||
for (entry in entries) {
|
||||
if (entry.action == MiniMenuAction.WALK_HERE && entry.subjectIndex == 0L) {
|
||||
hoverPickActive = true
|
||||
hoverPickScreenX = entry.intArg1
|
||||
hoverPickScreenY = entry.intArg2
|
||||
return
|
||||
}
|
||||
}
|
||||
clearExpiredHoverTargets(System.currentTimeMillis())
|
||||
}
|
||||
|
||||
private fun isHoverPicking(): Boolean {
|
||||
return isSmartRoofsActive() && hoverPickActive
|
||||
}
|
||||
|
||||
private fun getHoverPickScreenX(): Int = hoverPickScreenX
|
||||
|
||||
private fun getHoverPickScreenY(): Int = hoverPickScreenY
|
||||
|
||||
private fun setHoverTile(sceneX: Int, sceneZ: Int, plane: Int) {
|
||||
if (!isSmartRoofsActive() || !hoverPickActive || !isInSceneBounds(sceneX, sceneZ)) {
|
||||
return
|
||||
}
|
||||
val valid = updateHoverTarget(sceneX, sceneZ, Player.plane, plane)
|
||||
rememberHoverTileHit(sceneX, sceneZ, plane, valid)
|
||||
if (valid) {
|
||||
markHoverHit()
|
||||
return
|
||||
}
|
||||
clearExpiredHoverTargets(System.currentTimeMillis())
|
||||
}
|
||||
|
||||
private fun isHoverLocPickable(key: Long): Boolean {
|
||||
if (!isSmartRoofsActive() || !hoverPickActive || key == 0L) {
|
||||
return false
|
||||
}
|
||||
val entityType = (key.toInt() shr 29) and 0x3
|
||||
val locShape = ((key shr 14) and 0x3F).toInt()
|
||||
return entityType == 2 && isBuildingLocShape(locShape)
|
||||
}
|
||||
|
||||
private fun setHoverLoc(key: Long, plane: Int) {
|
||||
if (!isHoverLocPickable(key)) {
|
||||
return
|
||||
}
|
||||
val sceneX = (key and 0x7F).toInt()
|
||||
val sceneZ = ((key shr 7) and 0x7F).toInt()
|
||||
if (!isInSceneBounds(sceneX, sceneZ)) {
|
||||
return
|
||||
}
|
||||
if (updateHoverTarget(sceneX, sceneZ, Player.plane, plane)) {
|
||||
markHoverHit()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateHoverTarget(sceneX: Int, sceneZ: Int, plane: Int, hitPlane: Int): Boolean {
|
||||
var targetX = sceneX
|
||||
var targetZ = sceneZ
|
||||
val now = System.currentTimeMillis()
|
||||
if (!isHideableRoofTile(targetX, targetZ, plane)) {
|
||||
val packed = findNearbyHideableRoofTile(sceneX, sceneZ, plane, hitPlane)
|
||||
if (packed == -1) {
|
||||
return false
|
||||
}
|
||||
targetX = packed shr 7
|
||||
targetZ = packed and 0x7F
|
||||
}
|
||||
if (!isHideableRoofTile(targetX, targetZ, plane)) {
|
||||
return false
|
||||
}
|
||||
|
||||
val duplicateSlot = findHoverTargetByBuildingFootprint(targetX, targetZ, plane)
|
||||
if (duplicateSlot != -1) {
|
||||
updateHoverPrimaryHit(duplicateSlot)
|
||||
extendHoverTarget(duplicateSlot, now)
|
||||
return true
|
||||
}
|
||||
|
||||
var oldestSlot = 0
|
||||
var oldestUntil = Long.MAX_VALUE
|
||||
for (i in 0 until HOVER_TARGET_LIMIT) {
|
||||
if (hoverTargetX[i] == targetX && hoverTargetZ[i] == targetZ && hoverTargetPlane[i] == plane) {
|
||||
updateHoverPrimaryHit(i)
|
||||
extendHoverTarget(i, now)
|
||||
return true
|
||||
}
|
||||
if (hoverTargetX[i] == -1 || now > hoverTargetUntil[i]) {
|
||||
hoverTargetX[i] = targetX
|
||||
hoverTargetZ[i] = targetZ
|
||||
hoverTargetPlane[i] = plane
|
||||
clearBuildingFootprint(i)
|
||||
updateHoverPrimaryHit(i)
|
||||
extendHoverTarget(i, now)
|
||||
return true
|
||||
}
|
||||
if (hoverTargetUntil[i] < oldestUntil) {
|
||||
oldestUntil = hoverTargetUntil[i]
|
||||
oldestSlot = i
|
||||
}
|
||||
}
|
||||
hoverTargetX[oldestSlot] = targetX
|
||||
hoverTargetZ[oldestSlot] = targetZ
|
||||
hoverTargetPlane[oldestSlot] = plane
|
||||
clearBuildingFootprint(oldestSlot)
|
||||
updateHoverPrimaryHit(oldestSlot)
|
||||
extendHoverTarget(oldestSlot, now)
|
||||
return true
|
||||
}
|
||||
|
||||
private fun findNearbyHideableRoofTile(sceneX: Int, sceneZ: Int, plane: Int, hitPlane: Int): Int {
|
||||
if (hitPlane <= plane) {
|
||||
return -1
|
||||
}
|
||||
for (radius in 1..HOVER_UPPER_PLANE_TILE_SEARCH_RADIUS) {
|
||||
for (dx in -radius..radius) {
|
||||
for (dz in -radius..radius) {
|
||||
if (abs(dx) != radius && abs(dz) != radius) {
|
||||
continue
|
||||
}
|
||||
val targetX = sceneX + dx
|
||||
val targetZ = sceneZ + dz
|
||||
if (isHideableRoofTile(targetX, targetZ, plane)) {
|
||||
return (targetX shl 7) or targetZ
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
private fun rememberHoverTileHit(sceneX: Int, sceneZ: Int, plane: Int, valid: Boolean) {
|
||||
lastHoverTileX = sceneX
|
||||
lastHoverTileZ = sceneZ
|
||||
lastHoverTilePlane = plane
|
||||
lastHoverTileValid = valid
|
||||
lastHoverTileAt = System.currentTimeMillis()
|
||||
}
|
||||
|
||||
private fun markHoverHit() {
|
||||
lastHoverHitAt = System.currentTimeMillis()
|
||||
}
|
||||
|
||||
private fun clearHoverRequest() {
|
||||
hoverPickActive = false
|
||||
clearHoverTargets()
|
||||
}
|
||||
|
||||
private fun findHoverTargetByBuildingFootprint(sceneX: Int, sceneZ: Int, plane: Int): Int {
|
||||
for (i in 0 until HOVER_TARGET_LIMIT) {
|
||||
if (hoverTargetX[i] == -1 || hoverTargetPlane[i] != plane) {
|
||||
continue
|
||||
}
|
||||
if (isBuildingFootprintTile(i, sceneX, sceneZ)) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
private fun extendHoverTarget(index: Int, now: Long) {
|
||||
hoverTargetUntil[index] = now + HOVER_HOLD_MS
|
||||
}
|
||||
|
||||
private fun getHoverGroup(index: Int): Int = HOVER_GROUP_START + index
|
||||
|
||||
private fun getHoverIndex(group: Int): Int {
|
||||
val index = group - HOVER_GROUP_START
|
||||
return if (index >= 0 && index < HOVER_TARGET_LIMIT) index else -1
|
||||
}
|
||||
|
||||
private fun clearExpiredHoverTargets(now: Long) {
|
||||
for (i in 0 until HOVER_TARGET_LIMIT) {
|
||||
if (hoverTargetX[i] != -1 && now > hoverTargetUntil[i]) {
|
||||
if (isPickInsideBuildingFootprint(i)) {
|
||||
extendHoverTarget(i, now)
|
||||
continue
|
||||
}
|
||||
clearHoverTarget(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun clearHoverTargets() {
|
||||
for (i in 0 until HOVER_TARGET_LIMIT) {
|
||||
clearHoverTarget(i)
|
||||
}
|
||||
lastHoverTileX = -1
|
||||
lastHoverTileZ = -1
|
||||
lastHoverTilePlane = -1
|
||||
lastHoverTileValid = false
|
||||
lastHoverTileAt = 0L
|
||||
lastHoverHitAt = 0L
|
||||
}
|
||||
|
||||
private fun clearHoverTarget(index: Int) {
|
||||
hoverTargetX[index] = -1
|
||||
hoverTargetZ[index] = -1
|
||||
hoverTargetPlane[index] = -1
|
||||
hoverPrimaryHitX[index] = Int.MIN_VALUE
|
||||
hoverPrimaryHitY[index] = Int.MIN_VALUE
|
||||
hoverTargetUntil[index] = 0L
|
||||
clearBuildingFootprint(index)
|
||||
}
|
||||
|
||||
private fun hideHoverTargets() {
|
||||
val now = System.currentTimeMillis()
|
||||
val keepAlive = Cs1ScriptRunner.aBoolean108
|
||||
for (i in 0 until HOVER_TARGET_LIMIT) {
|
||||
if (hoverTargetX[i] == -1) {
|
||||
continue
|
||||
}
|
||||
val hasBuildingArea = hasBuildingFootprint(i)
|
||||
val buildingFootprintKeepAlive = isPickInsideBuildingFootprint(i)
|
||||
val primaryHitKeepAlive = isPickNearPrimaryHit(i, if (hasBuildingArea) HOVER_BUILDING_FOOTPRINT_PRIMARY_HIT_DISTANCE else HOVER_PRIMARY_HIT_DISTANCE)
|
||||
if (hasRecentOutsideGroundHit(i, now, buildingFootprintKeepAlive || hasBuildingArea && primaryHitKeepAlive)) {
|
||||
clearHoverTarget(i)
|
||||
continue
|
||||
}
|
||||
if (keepAlive || primaryHitKeepAlive || buildingFootprintKeepAlive) {
|
||||
extendHoverTarget(i, now)
|
||||
} else if (now > hoverTargetUntil[i]) {
|
||||
clearHoverTarget(i)
|
||||
continue
|
||||
}
|
||||
val group = getHoverGroup(i)
|
||||
hideRoofFromSeedTile(hoverTargetX[i], hoverTargetZ[i], 0, group, hoverTargetPlane[i])
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateHoverPrimaryHit(index: Int) {
|
||||
hoverPrimaryHitX[index] = hoverPickScreenX
|
||||
hoverPrimaryHitY[index] = hoverPickScreenY
|
||||
}
|
||||
|
||||
private fun isPickNearPrimaryHit(index: Int, distance: Int): Boolean {
|
||||
if (!hoverPickActive || hoverPrimaryHitX[index] == Int.MIN_VALUE) {
|
||||
return false
|
||||
}
|
||||
val dx = hoverPickScreenX - hoverPrimaryHitX[index]
|
||||
val dy = hoverPickScreenY - hoverPrimaryHitY[index]
|
||||
return dx * dx + dy * dy <= distance * distance
|
||||
}
|
||||
|
||||
private fun isPickInsideBuildingFootprint(index: Int): Boolean {
|
||||
if (!hoverPickActive || !hasBuildingFootprint(index)) {
|
||||
return false
|
||||
}
|
||||
for (x in 0 until 104) {
|
||||
for (z in 0 until 104) {
|
||||
if (buildingFootprintTiles[index][x][z] && isPickInsideBuildingFootprintTile(index, x, z)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun hasBuildingFootprint(index: Int): Boolean {
|
||||
return buildingFootprintMinX[index] != Int.MAX_VALUE
|
||||
}
|
||||
|
||||
private fun clearBuildingFootprint(index: Int) {
|
||||
buildingFootprintMinX[index] = Int.MAX_VALUE
|
||||
buildingFootprintMaxX[index] = Int.MIN_VALUE
|
||||
buildingFootprintMinY[index] = Int.MAX_VALUE
|
||||
buildingFootprintMaxY[index] = Int.MIN_VALUE
|
||||
for (x in 0 until 104) {
|
||||
buildingFootprintTiles[index][x].fill(false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun beginBuildingFootprint(group: Int) {
|
||||
val index = getHoverIndex(group)
|
||||
if (index != -1) {
|
||||
clearBuildingFootprint(index)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addBuildingFootprintTile(group: Int, plane: Int, sceneX: Int, sceneZ: Int) {
|
||||
val index = getHoverIndex(group)
|
||||
if (index == -1 || plane + 1 >= SceneGraph.tileHeights.size) {
|
||||
return
|
||||
}
|
||||
buildingFootprintTiles[index][sceneX][sceneZ] = true
|
||||
addBuildingFootprintTileBounds(index, plane, sceneX, sceneZ)
|
||||
}
|
||||
|
||||
private fun addBuildingFootprintTileBounds(index: Int, plane: Int, sceneX: Int, sceneZ: Int) {
|
||||
addBuildingFootprintBoundPoint(index, projectBuildingFootprintPoint(sceneX shl 7, sceneZ shl 7, SceneGraph.tileHeights[plane + 1][sceneX][sceneZ]))
|
||||
addBuildingFootprintBoundPoint(index, projectBuildingFootprintPoint((sceneX + 1) shl 7, sceneZ shl 7, SceneGraph.tileHeights[plane + 1][sceneX + 1][sceneZ]))
|
||||
addBuildingFootprintBoundPoint(index, projectBuildingFootprintPoint((sceneX + 1) shl 7, (sceneZ + 1) shl 7, SceneGraph.tileHeights[plane + 1][sceneX + 1][sceneZ + 1]))
|
||||
addBuildingFootprintBoundPoint(index, projectBuildingFootprintPoint(sceneX shl 7, (sceneZ + 1) shl 7, SceneGraph.tileHeights[plane + 1][sceneX][sceneZ + 1]))
|
||||
}
|
||||
|
||||
private fun isPickInsideBuildingFootprintTile(index: Int, sceneX: Int, sceneZ: Int): Boolean {
|
||||
val plane = hoverTargetPlane[index]
|
||||
if (!isRoofHidePlane(plane) || plane + 1 >= SceneGraph.tileHeights.size) {
|
||||
return false
|
||||
}
|
||||
val point0 = projectBuildingFootprintPoint(sceneX shl 7, sceneZ shl 7, SceneGraph.tileHeights[plane + 1][sceneX][sceneZ])
|
||||
val point1 = projectBuildingFootprintPoint((sceneX + 1) shl 7, sceneZ shl 7, SceneGraph.tileHeights[plane + 1][sceneX + 1][sceneZ])
|
||||
val point2 = projectBuildingFootprintPoint((sceneX + 1) shl 7, (sceneZ + 1) shl 7, SceneGraph.tileHeights[plane + 1][sceneX + 1][sceneZ + 1])
|
||||
val point3 = projectBuildingFootprintPoint(sceneX shl 7, (sceneZ + 1) shl 7, SceneGraph.tileHeights[plane + 1][sceneX][sceneZ + 1])
|
||||
if (point0 == Long.MIN_VALUE || point1 == Long.MIN_VALUE || point2 == Long.MIN_VALUE || point3 == Long.MIN_VALUE) {
|
||||
return false
|
||||
}
|
||||
val minX = min(min((point0 shr 32).toInt(), (point1 shr 32).toInt()), min((point2 shr 32).toInt(), (point3 shr 32).toInt()))
|
||||
val maxX = max(max((point0 shr 32).toInt(), (point1 shr 32).toInt()), max((point2 shr 32).toInt(), (point3 shr 32).toInt()))
|
||||
val minY = min(min(point0.toInt(), point1.toInt()), min(point2.toInt(), point3.toInt()))
|
||||
val maxY = max(max(point0.toInt(), point1.toInt()), max(point2.toInt(), point3.toInt()))
|
||||
return hoverPickScreenX >= minX - HOVER_BUILDING_FOOTPRINT_X_PADDING &&
|
||||
hoverPickScreenX <= maxX + HOVER_BUILDING_FOOTPRINT_X_PADDING &&
|
||||
hoverPickScreenY >= minY - HOVER_BUILDING_FOOTPRINT_TOP_PADDING &&
|
||||
hoverPickScreenY <= maxY + HOVER_BUILDING_FOOTPRINT_BOTTOM_PADDING
|
||||
}
|
||||
|
||||
private fun hasRecentOutsideGroundHit(index: Int, now: Long, pickInsideBuildingFootprint: Boolean): Boolean {
|
||||
if (pickInsideBuildingFootprint || lastHoverTileAt == 0L || now - lastHoverTileAt > HOVER_OUTSIDE_GROUND_HIT_MS) {
|
||||
return false
|
||||
}
|
||||
if (lastHoverTileValid || lastHoverTileAt <= lastHoverHitAt || now - lastHoverHitAt <= HOVER_OUTSIDE_GROUND_HIT_MS) {
|
||||
return false
|
||||
}
|
||||
if (lastHoverTilePlane != hoverTargetPlane[index]) {
|
||||
return false
|
||||
}
|
||||
return !isBuildingFootprintTile(index, lastHoverTileX, lastHoverTileZ)
|
||||
}
|
||||
|
||||
private fun isBuildingFootprintTile(index: Int, sceneX: Int, sceneZ: Int): Boolean {
|
||||
return isInSceneBounds(sceneX, sceneZ) && buildingFootprintTiles[index][sceneX][sceneZ]
|
||||
}
|
||||
|
||||
private fun addBuildingFootprintBoundPoint(index: Int, packedPoint: Long) {
|
||||
if (packedPoint == Long.MIN_VALUE) {
|
||||
return
|
||||
}
|
||||
val screenX = (packedPoint shr 32).toInt()
|
||||
val screenY = packedPoint.toInt()
|
||||
if (screenX < buildingFootprintMinX[index]) {
|
||||
buildingFootprintMinX[index] = screenX
|
||||
}
|
||||
if (screenX > buildingFootprintMaxX[index]) {
|
||||
buildingFootprintMaxX[index] = screenX
|
||||
}
|
||||
if (screenY < buildingFootprintMinY[index]) {
|
||||
buildingFootprintMinY[index] = screenY
|
||||
}
|
||||
if (screenY > buildingFootprintMaxY[index]) {
|
||||
buildingFootprintMaxY[index] = screenY
|
||||
}
|
||||
}
|
||||
|
||||
private fun projectBuildingFootprintPoint(xFine: Int, zFine: Int, yFine: Int): Long {
|
||||
val localX = xFine - Camera.renderX
|
||||
val localY = yFine - Camera.anInt40
|
||||
val localZ = zFine - Camera.renderZ
|
||||
val sinPitch = MathUtils.sin[Camera.cameraPitch]
|
||||
val cosPitch = MathUtils.cos[Camera.cameraPitch]
|
||||
val sinYaw = MathUtils.sin[Camera.cameraYaw]
|
||||
val cosYaw = MathUtils.cos[Camera.cameraYaw]
|
||||
val rotatedX = localX * cosYaw + localZ * sinYaw shr 16
|
||||
val rotatedZ = localZ * cosYaw - localX * sinYaw shr 16
|
||||
val screenYDepth = rotatedZ * cosPitch + localY * sinPitch shr 16
|
||||
if (screenYDepth < 50) {
|
||||
return Long.MIN_VALUE
|
||||
}
|
||||
val rotatedY = localY * cosPitch - rotatedZ * sinPitch shr 16
|
||||
val screenX = (rotatedX shl 9) / screenYDepth
|
||||
val screenY = (rotatedY shl 9) / screenYDepth
|
||||
return (screenX.toLong() shl 32) or (screenY.toLong() and 0xFFFFFFFFL)
|
||||
}
|
||||
|
||||
fun setDestinationTarget(sceneX: Int, sceneZ: Int) {
|
||||
if (!isSmartRoofsActive()) {
|
||||
clearDestinationTarget()
|
||||
return
|
||||
}
|
||||
if (!isInSceneBounds(sceneX, sceneZ)) {
|
||||
clearDestinationTarget()
|
||||
return
|
||||
}
|
||||
destinationTargetX = sceneX
|
||||
destinationTargetZ = sceneZ
|
||||
destinationTargetUntil = System.currentTimeMillis() + DESTINATION_HOLD_MS
|
||||
}
|
||||
|
||||
fun clearDestinationTarget() {
|
||||
destinationTargetX = -1
|
||||
destinationTargetZ = -1
|
||||
destinationTargetUntil = 0L
|
||||
}
|
||||
|
||||
private fun hasDestinationTarget(): Boolean {
|
||||
if (destinationTargetX == -1) {
|
||||
return false
|
||||
}
|
||||
if (System.currentTimeMillis() > destinationTargetUntil) {
|
||||
clearDestinationTarget()
|
||||
return false
|
||||
}
|
||||
val self = PlayerList.self
|
||||
if (self != null &&
|
||||
abs(self.movementQueueX[0] - destinationTargetX) <= DESTINATION_REACHED_DISTANCE &&
|
||||
abs(self.movementQueueZ[0] - destinationTargetZ) <= DESTINATION_REACHED_DISTANCE
|
||||
) {
|
||||
clearDestinationTarget()
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun hideDestinationTarget() {
|
||||
if (hasDestinationTarget()) {
|
||||
hideRoofFromSeedTile(destinationTargetX, destinationTargetZ, 0, DESTINATION_TARGET_GROUP, Player.plane)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isInSceneBounds(sceneX: Int, sceneZ: Int): Boolean {
|
||||
return sceneX in 0 until 104 && sceneZ in 0 until 104
|
||||
}
|
||||
|
||||
private fun isHideableRoofTile(sceneX: Int, sceneZ: Int, plane: Int): Boolean {
|
||||
if (ScriptRunner.aByteArrayArrayArray15 == null) {
|
||||
return false
|
||||
}
|
||||
return isRoofHidePlane(plane) &&
|
||||
isInSceneBounds(sceneX, sceneZ) &&
|
||||
(SceneGraph.renderFlags[plane][sceneX][sceneZ].toInt() and TILE_FLAG_UNDER_ROOF) != 0
|
||||
}
|
||||
|
||||
private fun isRoofHidePlane(plane: Int): Boolean {
|
||||
return plane in 0 until 3
|
||||
}
|
||||
|
||||
private fun isBuildingLocShape(shape: Int): Boolean {
|
||||
return shape == LocType.WALL_STRAIGHT ||
|
||||
shape == LocType.WALL_DIAGONALCORNER ||
|
||||
shape == LocType.WALL_L ||
|
||||
shape == LocType.WALL_SQUARECORNER ||
|
||||
shape == LocType.WALL_DIAGONAL ||
|
||||
shape == LocType.WALLDECOR_STRAIGHT_XOFFSET ||
|
||||
shape == LocType.WALLDECOR_STRAIGHT_ZOFFSET ||
|
||||
shape == LocType.WALLDECOR_DIAGONAL_XOFFSET ||
|
||||
shape == LocType.WALLDECOR_DIAGONAL_ZOFFSET ||
|
||||
shape == LocType.WALLDECOR_DIAGONAL_BOTH
|
||||
}
|
||||
|
||||
}
|
||||
51
plugin-playground/src/main/kotlin/SmartRoofs/plugin.kt
Normal file
51
plugin-playground/src/main/kotlin/SmartRoofs/plugin.kt
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
package SmartRoofs
|
||||
|
||||
import plugin.Plugin
|
||||
import plugin.api.API
|
||||
import plugin.api.MiniMenuEntry
|
||||
|
||||
class plugin : Plugin() {
|
||||
override fun Init() {
|
||||
API.SetRoofVisibilityHandler(RoofHider.HANDLER)
|
||||
}
|
||||
|
||||
override fun Draw(timeDelta: Long) {
|
||||
if (!API.IsLoggedIn()) {
|
||||
clearTargets()
|
||||
return
|
||||
}
|
||||
API.SetRoofVisibilityHandler(RoofHider.HANDLER)
|
||||
RoofHider.setSmartRoofsEnabled(true)
|
||||
RoofHider.updateSmartRoofs()
|
||||
|
||||
val mapFlag = API.GetMapFlagTile()
|
||||
if (mapFlag == null) {
|
||||
RoofHider.clearMapFlagRoof()
|
||||
} else {
|
||||
RoofHider.setMapFlagRoof(mapFlag[0], mapFlag[1], MAP_FLAG_RADIUS)
|
||||
}
|
||||
}
|
||||
|
||||
override fun OnMiniMenuCreate(currentEntries: Array<out MiniMenuEntry>?) {
|
||||
RoofHider.updateHoverPick(currentEntries)
|
||||
}
|
||||
|
||||
override fun OnLogout() {
|
||||
clearTargets()
|
||||
}
|
||||
|
||||
override fun OnPluginsReloaded(): Boolean {
|
||||
clearTargets()
|
||||
API.ClearRoofVisibilityHandler(RoofHider.HANDLER)
|
||||
return false
|
||||
}
|
||||
|
||||
private fun clearTargets() {
|
||||
RoofHider.clearMapFlagRoof()
|
||||
RoofHider.setSmartRoofsEnabled(false)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val MAP_FLAG_RADIUS = 0
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
AUTHOR='Edith'
|
||||
DESCRIPTION='Hides roofs on cursor hover and destination travel.'
|
||||
VERSION=1.0
|
||||
Loading…
Add table
Add a link
Reference in a new issue