Emberveil sourcetests/OnlineSmoke.java
import java.net.InetAddress;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
/** External VPS acceptance check; temporary QA accounts only, never owner credentials. */
public class OnlineSmoke extends Game {
static String host, username, peer;
static int targetTicks=Integer.getInteger("emberveil.qaTicks",1800);
int ticks, startX, startY;
boolean attempted, moved, sawPeer, sawChat, welcome;
boolean cyanHeader,cyanPvm,cyanPvp,chestVisible,chestOpened,chestDeposited,chestWithdrew;
int depositSlot=-1,depositId,depositCount;
boolean goblinListed,goblinJournal,staffDenied,monkListed,monkJournal,romeoListed,romeoJournal,fishingListed,fishingJournal;
boolean clockListed,clockJournal,totemListed,totemJournal,ownerSlayerDenied;
void bankClick(int widget,int slot,int id){stream.createFrame(145);stream.method432(widget);stream.method432(slot);stream.method432(id);}
boolean testWalking=true, testChat=true;
@Override public void resetLogout() {
if(attempted && ticks>0) {
System.err.println("FAIL unexpected logout at test tick "+ticks+" packet="+pktType);
new Exception("Logout call site").printStackTrace();
System.exit(3);
}
super.resetLogout();
}
@Override public void dropClient() {
System.err.println("FAIL dropped connection at test tick "+ticks+" packet="+pktType);
new Exception("Connection drop call site").printStackTrace();
System.exit(4);
}
void chat() {
stream.createFrame(4); stream.writeWordBigEndian(0);
int offset=stream.currentOffset;
stream.method425(0); stream.method425(0);
aStream_834.currentOffset=0;
TextInput.method526("emberveil online test", aStream_834);
stream.method441(0,aStream_834.buffer,aStream_834.currentOffset);
stream.writeBytes(stream.currentOffset-offset);
}
@Override public void processGameLoop() {
if(!attempted) {
attempted=true; myUsername=username; myPassword=System.getProperty("emberveil.qaPassword");
if(myPassword==null) throw new IllegalArgumentException("QA password required");
loginScreenState=2; login(myUsername,myPassword,false);
if(!loggedIn) { System.err.println("FAIL login: "+loginMessage1+" "+loginMessage2); System.exit(1); }
System.out.println("Encrypted public VPS login succeeded: "+username);
}
super.processGameLoop();
if(!loggedIn || loadingStage!=2) return;
ticks++;
if(ticks==20 || (Boolean.getBoolean("emberveil.checkGreenUpdate")&&openInterfaceID==3559&&ticks%40==0)) {
for(RSInterface widget: RSInterface.interfaceCache) {
if(widget!=null && widget.anInt214==326) { System.out.println("Accepting character design: tick="+ticks+" interface="+openInterfaceID+" button="+widget.id);if(promptUserForInput(widget)){stream.createFrame(185);stream.writeWord(widget.id);} break; }
}
}
for(Player player:playerArray) if(player!=null && player.name!=null && player.name.equalsIgnoreCase(peer)) sawPeer=true;
for(String message:chatMessages) if(message!=null) {
if(message.contains("Slayer teleport is only available to owner bonds"))ownerSlayerDenied=true;
if(message.contains("teleport is for Emberveil's owner and co-owner"))staffDenied=true;
if(message.contains("Welcome to") && message.contains("bonds")) welcome=true;
if(message.startsWith("@cya@")&&message.contains("Welcome to")&&message.contains("bonds"))cyanHeader=true;
if(message.startsWith("@cya@")&&message.contains("PvM")&&message.contains("Slayer"))cyanPvm=true;
if(message.startsWith("@cya@")&&message.contains("Wilderness")&&message.contains("PvP"))cyanPvp=true;
if(message.toLowerCase().contains("emberveil online test")) sawChat=true;
}
if(ticks==100 && testWalking) {
startX=myPlayer.smallX[0]; startY=myPlayer.smallY[0];
doWalkTo(0,0,0,0,startY,0,0,startY,startX,true,startX+1);
}
if(ticks>100 && (myPlayer.smallX[0]!=startX || myPlayer.smallY[0]!=startY)) moved=true;
if(testChat && (ticks==200 || ticks==400)) chat();
if(Boolean.getBoolean("emberveil.checkDarrenUpdate")) {
if(ticks==300)goblinListed=RSInterface.interfaceCache[7338]!=null&&RSInterface.interfaceCache[7338].disabledText.contains("Goblin Diplomacy");
if(ticks==800){String command="staffzone";stream.createFrame(103);stream.writeWordBigEndian(command.length()+1);stream.writeString(command);}
if(ticks==850){stream.createFrame(185);stream.writeWord(7338);}
if(ticks==910){goblinJournal=openInterfaceID==8134&&RSInterface.interfaceCache[8144].disabledText.contains("Goblin Diplomacy");closeOpenInterfaces();}
}
if(Boolean.getBoolean("emberveil.checkShortQuest")) {
if(ticks==940){monkListed=RSInterface.interfaceCache[7369]!=null&&RSInterface.interfaceCache[7369].disabledText.contains("Monk's Friend");stream.createFrame(185);stream.writeWord(7369);}
if(ticks==1010){monkJournal=openInterfaceID==8134&&RSInterface.interfaceCache[8144].disabledText.contains("Monk's Friend");closeOpenInterfaces();}
}
if(Boolean.getBoolean("emberveil.checkRomeoQuest")) {
if(ticks==1060){romeoListed=RSInterface.interfaceCache[7343]!=null&&RSInterface.interfaceCache[7343].disabledText.contains("Romeo");stream.createFrame(185);stream.writeWord(7343);}
if(ticks==1120){romeoJournal=openInterfaceID==8134&&RSInterface.interfaceCache[8144].disabledText.contains("Romeo");closeOpenInterfaces();}
}
if(Boolean.getBoolean("emberveil.checkFishingQuest")) {
if(ticks==1180){fishingListed=RSInterface.interfaceCache[7359]!=null&&RSInterface.interfaceCache[7359].disabledText.contains("Fishing Contest");stream.createFrame(185);stream.writeWord(7359);}
if(ticks==1240){fishingJournal=openInterfaceID==8134&&RSInterface.interfaceCache[8144].disabledText.contains("Fishing Contest");closeOpenInterfaces();}
}
if(ticks%1000==0) System.out.println("Still connected: "+username+" ticks="+ticks);
if(Boolean.getBoolean("emberveil.checkClockQuest")) {
if(ticks==1280){clockListed=RSInterface.interfaceCache[7353]!=null&&RSInterface.interfaceCache[7353].disabledText.contains("Clock Tower");stream.createFrame(185);stream.writeWord(7353);}
if(ticks==1360){clockJournal=openInterfaceID==8134&&RSInterface.interfaceCache[8144].disabledText.contains("Clock Tower");closeOpenInterfaces();}
}
if(Boolean.getBoolean("emberveil.checkTotemQuest")) {
if(ticks==1400){totemListed=RSInterface.interfaceCache[7381]!=null&&RSInterface.interfaceCache[7381].disabledText.contains("Tribal Totem");stream.createFrame(185);stream.writeWord(7381);}
if(ticks==1480){totemJournal=openInterfaceID==8134&&RSInterface.interfaceCache[8144].disabledText.contains("Tribal Totem");closeOpenInterfaces();}
}
if(ticks==500 && Boolean.getBoolean("emberveil.checkNewClient")){tabID=7;needDrawTabArea=true;tabAreaAltered=true;}
if(Boolean.getBoolean("emberveil.checkGreenUpdate")) {
if(ticks==300)chestVisible=(worldController.method302(plane,3231-baseX,3227-baseY)>>14&0x7fff)==4483;
if(ticks==450)doWalkTo(0,0,0,0,myPlayer.smallY[0],0,0,3227-baseY,myPlayer.smallX[0],true,3232-baseX);
if(ticks==520){stream.createFrame(132);stream.method433(3231);stream.writeWord(4483);stream.method432(3227);}
if(ticks==600){
chestOpened=openInterfaceID==5292;
if(!chestOpened){System.err.println("FAIL spawn chest did not open; visible="+chestVisible+" position="+(baseX+myPlayer.smallX[0])+","+(baseY+myPlayer.smallY[0])+","+plane+" interface="+openInterfaceID);for(String line:chatMessages)if(line!=null)System.err.println("QA chat: "+line);System.exit(1);}
RSInterface inv=RSInterface.interfaceCache[5064];
for(int i=0;i<inv.inv.length;i++)if(inv.inv[i]==996){depositSlot=i;depositId=995;depositCount=inv.invStackSizes[i];break;}
if(depositSlot<0)for(int i=0;i<inv.inv.length;i++)if(inv.inv[i]>0){depositSlot=i;depositId=inv.inv[i]-1;depositCount=inv.invStackSizes[i];break;}
if(depositSlot<0)throw new AssertionError("No starter item for deposit test");
bankClick(5064,depositSlot,depositId);
}
if(ticks==660){RSInterface bank=RSInterface.interfaceCache[5382];for(int i=0;i<bank.inv.length;i++)if(bank.inv[i]==depositId+1&&bank.invStackSizes[i]>=1){chestDeposited=true;bankClick(5382,i,depositId);break;}}
if(ticks==730){RSInterface inv=RSInterface.interfaceCache[5064];for(int i=0;i<inv.inv.length;i++)if(inv.inv[i]==depositId+1&&inv.invStackSizes[i]>=depositCount)chestWithdrew=true;closeOpenInterfaces();}
}
if(Boolean.getBoolean("emberveil.checkOwnerSlayer") && ticks==850){String command="slayertask";stream.createFrame(103);stream.writeWordBigEndian(command.length()+1);stream.writeString(command);}
if(Boolean.getBoolean("emberveil.checkOwnerSlayer") && ticks==880){String command="slayzone";stream.createFrame(103);stream.writeWordBigEndian(command.length()+1);stream.writeString(command);}
// Visual fixture only: never changes the QA account on the server.
if(Boolean.getBoolean("emberveil.checkFireHat") && ticks==900){
myPlayer.name="Bonds";myPlayer.equipment[0]=14999+512;
try{java.lang.reflect.Field f=Player.class.getDeclaredField("aLong1718");f.setAccessible(true);f.setLong(myPlayer,789010380512L);}catch(Exception e){throw new RuntimeException(e);}
System.out.println("Client-only equipped fire-partyhat visual fixture enabled");
}
if(ticks==targetTicks) {
try {
BufferedImage screenshot=new BufferedImage(512,334,BufferedImage.TYPE_INT_RGB);
screenshot.setRGB(0,0,512,334,aRSImageProducer_1165.anIntArray315,0,512);
ImageIO.write(screenshot,"png",new File("runtime/online-"+username+".png"));
boolean pass=moved && sawPeer && sawChat && welcome;
if(Boolean.getBoolean("emberveil.checkOwnerSlayer")){pass &= ownerSlayerDenied;System.out.println("Owner Slayer teleport denied to QA account: "+ownerSlayerDenied);}
if(Boolean.getBoolean("emberveil.checkFireHat")){boolean hat=FirePartyhat.wearing(myPlayer)&&myPlayer.getRotatedModel()!=null;pass &= hat;System.out.println("Client-only equipped fire-partyhat render fixture: "+hat);}
if(Boolean.getBoolean("emberveil.checkTotemQuest")){pass &= totemListed&&totemJournal;System.out.println("Tribal Totem live journal: listed="+totemListed+" journal="+totemJournal);}
if(Boolean.getBoolean("emberveil.checkClockQuest")){pass &= clockListed&&clockJournal;System.out.println("Clock Tower live journal: listed="+clockListed+" journal="+clockJournal);}
if(Boolean.getBoolean("emberveil.checkFishingQuest")){pass &= fishingListed&&fishingJournal;System.out.println("Fishing Contest live journal: listed="+fishingListed+" journal="+fishingJournal);}
if(Boolean.getBoolean("emberveil.checkRomeoQuest")){pass &= romeoListed&&romeoJournal;System.out.println("Romeo and Juliet live journal: listed="+romeoListed+" journal="+romeoJournal);}
if(Boolean.getBoolean("emberveil.checkShortQuest")){pass &= monkListed&&monkJournal;System.out.println("Monks Friend live journal: listed="+monkListed+" journal="+monkJournal);}
if(Boolean.getBoolean("emberveil.checkGreenUpdate")) {
int green=0;for(int pixel:aRSImageProducer_1163.anIntArray315)if((pixel>>8&255)>200&&(pixel>>8&255)>(pixel>>16&255))green++;
pass &= cyanHeader&&cyanPvm&&cyanPvp&&chestVisible&&chestOpened&&chestDeposited&&chestWithdrew&&green>200;
BufferedImage panel=new BufferedImage(190,261,BufferedImage.TYPE_INT_RGB);panel.setRGB(0,0,190,261,aRSImageProducer_1163.anIntArray315,0,190);ImageIO.write(panel,"png",new File("runtime/green-tab-live-"+username+".png"));
System.out.println("Green update verified: cyan="+(cyanHeader&&cyanPvm&&cyanPvp)+" chestVisible="+chestVisible+" chestBank="+chestOpened+" deposited="+chestDeposited+" withdrew="+chestWithdrew+" greenPixels="+green);
}
if(Boolean.getBoolean("emberveil.checkNewClient")) {
if(Boolean.getBoolean("emberveil.checkDarrenUpdate")) {
pass &= goblinListed&&goblinJournal&&staffDenied&&baseY+myPlayer.smallY[0]<4000;
System.out.println("Darren/free quest verified: goblinListed="+goblinListed+" journal="+goblinJournal+" staffTeleportDenied="+staffDenied);
}
java.lang.reflect.Field iconField=Game.class.getDeclaredField("slayerTabIcon");iconField.setAccessible(true);Sprite icon=(Sprite)iconField.get(this);
pass &= icon!=null && icon.width==24 && icon.height==28 && variousSettings[1907]==1;
java.lang.reflect.Field barField=Game.class.getDeclaredField("aRSImageProducer_1124");barField.setAccessible(true);RSImageProducer bar=(RSImageProducer)barField.get(this);
BufferedImage tabs=new BufferedImage(269,37,BufferedImage.TYPE_INT_RGB);tabs.setRGB(0,0,269,37,bar.anIntArray315,0,269);ImageIO.write(tabs,"png",new File("runtime/slayer-tab-live.png"));
System.out.println("New client icon and player information verified: "+pass);
}
System.out.println((pass?"PASS":"FAIL")+" "+username+" world=rendered movement="+moved+" peer="+sawPeer+" chat="+sawChat+" ownerWelcome="+welcome+" position="+(baseX+myPlayer.smallX[0])+","+(baseY+myPlayer.smallY[0])+","+plane);
if(pass && Boolean.getBoolean("emberveil.checkGreenUpdate")) {java.awt.EventQueue.invokeLater(()->windowClosing(new java.awt.event.WindowEvent(gameFrame,java.awt.event.WindowEvent.WINDOW_CLOSING)));return;}
System.exit(pass?0:1);
} catch(Exception error) { error.printStackTrace(); System.exit(1); }
}
}
public static void main(String[] args)throws Exception {
host=args[0]; username=args[1]; peer=args[2];
if(!username.matches("evnet[0-9]{1,6}[ab]") || !peer.matches("evnet[0-9]{1,6}[ab]")) throw new IllegalArgumentException("Temporary QA accounts only");
ClientSettings.SERVER_IP=host; ClientSettings.SERVER_WORLD=1; ClientSettings.CHECK_CRC=false;
ClientSettings.SHOW_NAVBAR=false; ClientSettings.HIDE_ROOFS=true;
ClientSettings.CUSTOM_SETTINGS_TAB=Boolean.getBoolean("emberveil.checkNewClient");
Game.nodeID=10; Game.portOff=0; Game.setHighMem(); Game.isMembers=true;
Signlink.storeid=32; Signlink.startpriv(InetAddress.getLocalHost());
OnlineSmoke client=new OnlineSmoke();
client.createClientFrame(503,765);
client.gameFrame.setVisible(false);
Thread timeout=new Thread(()->{try{Thread.sleep(targetTicks*20L+60000);}catch(Exception ignored){} System.err.println("FAIL: online test timeout"); System.exit(2);});
timeout.setDaemon(true); timeout.start();
}
}