Emberveil source

mobile/java/MobileMain.java

import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.net.*;
import java.io.*;
import java.nio.file.*;

/** Local browser evaluation entry point. No desktop client or server files are modified. */
public final class MobileMain {
    private static MobileGame game;
    private static volatile String phase="Not started";
    private static volatile boolean signingIn;
    private static volatile String[] pendingLogin;
    private static final java.util.concurrent.ConcurrentLinkedQueue<int[]> drags=new java.util.concurrent.ConcurrentLinkedQueue<int[]>();
    private static final java.util.concurrent.ConcurrentLinkedQueue<int[]> taps=new java.util.concurrent.ConcurrentLinkedQueue<int[]>();
    static final class MobileGame extends Game {
        volatile boolean ready;
        volatile boolean reconnecting;
        @Override public void dropClient(){reconnecting=true;try{super.dropClient();}finally{reconnecting=false;}}
        int[] activeTap; int tapTicks;
        @Override public void processGameLoop(){
            String[] request=pendingLogin;
            if(request!=null){pendingLogin=null;try{myUsername=request[0];myPassword=request[1];loginScreenState=2;login(request[0],request[1],false);}finally{request[1]="";signingIn=false;}}
            if(activeTap==null){activeTap=taps.poll();if(activeTap!=null){movePointer(activeTap[0],activeTap[1]);tapTicks=2;}}
            else if(--tapTicks<=0){pressPointer(activeTap[0],activeTap[1],activeTap[2]);activeTap=null;}
            for(int count=0;count<12;count++){int[] drag=drags.poll();if(drag==null)break;applyGesture(drag);}
            super.processGameLoop();
        }
        @Override void drawLoadingText(int percent,String text){phase=text;super.drawLoadingText(percent,text);}
        @Override public Socket openSocket(int port)throws IOException{return new BrowserSocket(port);}
        @Override void startUp(){super.startUp();ready=true;phase="Ready to sign in";}
    }
    public static synchronized void start(String assetRoot)throws Exception {
        if(game!=null)return;
        phase="Preparing game files";
        String version="2026-10-16-ammunition-v2";
        Path cache=Paths.get("/files/emberveil-mobile",version);Files.createDirectories(cache);
        String[] files={"main_file_cache.dat","main_file_cache.idx0","main_file_cache.idx1","main_file_cache.idx2","main_file_cache.idx3","main_file_cache.idx4"};
        for(String file:files){Path from=Paths.get(assetRoot,file),to=cache.resolve(file);if(!Files.exists(to)||Files.size(to)!=Files.size(from))Files.copy(from,to,StandardCopyOption.REPLACE_EXISTING);}
        System.setProperty("emberveil.cache",cache.toString());
        System.setProperty("emberveil.browser","true");
        ClientSettings.SERVER_IP="127.0.0.1";ClientSettings.SERVER_WORLD=1;ClientSettings.CHECK_CRC=false;
        ClientSettings.SHOW_NAVBAR=false;ClientSettings.CUSTOM_SETTINGS_TAB=true;ClientSettings.CONTROL_KEY_ZOOMING=false;
        ClientSettings.BILINEAR_MINIMAP_FILTERING=true;ClientSettings.FIX_TRANSPARENCY_OVERFLOW=true;ClientSettings.FULL_512PX_VIEWPORT=true;
        ClientSettings.SNOW_FLOOR_ENABLED=false;ClientSettings.SNOW_FLOOR_FORCE_ENABLED=false;ClientSettings.SNOW_OVERLAY_FORCE_ENABLED=false;ClientSettings.SNOW_OVERLAY_ENABLED=false;ClientSettings.HIDE_ROOFS=true;
        Game.nodeID=10;Game.portOff=0;Game.setHighMem();Game.isMembers=true;Signlink.storeid=32;Signlink.startpriv(InetAddress.getByName("127.0.0.1"));
        phase="Loading Emberveil";game=new MobileGame();game.createClientFrame(503,765);
    }
    public static String status(){
        if(signingIn)return "Connecting";
        if(game!=null&&game.reconnecting)return "Reconnecting to Emberveil";
        if(game!=null&&game.loggedIn)return "In game";
        if(game!=null&&game.ready&&game.loginMessage2!=null&&!game.loginMessage2.isEmpty())return game.loginMessage1+" "+game.loginMessage2;
        return phase;
    }
    public static boolean ready(){return game!=null&&game.ready;}
    public static boolean loggedIn(){return game!=null&&game.loggedIn;}
    public static boolean busy(){return signingIn||(game!=null&&game.reconnecting);}
    public static synchronized void signIn(String username,String password){
        if(!ready()||game.loggedIn||busy())return;
        if(username==null||password==null||username.length()<1||username.length()>12||password.length()<1||password.length()>20)return;
        signingIn=true;pendingLogin=new String[]{username,password};
    }
    public static void point(int x,int y,int button){
        if(!ready()||x<0||y<0||x>=765||y>=503)return;
        if(taps.size()<8)taps.add(new int[]{x,y,button});
    }
    private static int rawX(int x){return (int)Math.round(x*game.displayScale()+(game.getWidth()-765*game.displayScale())/2);}
    private static int rawY(int y){return (int)Math.round(y*game.displayScale()+(game.getHeight()-503*game.displayScale())/2);}
    private static void movePointer(int x,int y){game.mouseMoved(new MouseEvent(game,MouseEvent.MOUSE_MOVED,System.currentTimeMillis(),0,rawX(x),rawY(y),0,false));}
    private static void pressPointer(int x,int y,int button){
        int rawX=(int)Math.round(x*game.displayScale()+(game.getWidth()-765*game.displayScale())/2);
        int rawY=(int)Math.round(y*game.displayScale()+(game.getHeight()-503*game.displayScale())/2);
        int mouseButton=button==2?MouseEvent.BUTTON3:MouseEvent.BUTTON1;
        game.mouseMoved(new MouseEvent(game,MouseEvent.MOUSE_MOVED,System.currentTimeMillis(),0,rawX,rawY,0,false));
        game.mousePressed(new MouseEvent(game,MouseEvent.MOUSE_PRESSED,System.currentTimeMillis(),0,rawX,rawY,1,button==2,mouseButton));
        game.mouseReleased(new MouseEvent(game,MouseEvent.MOUSE_RELEASED,System.currentTimeMillis(),0,rawX,rawY,1,button==2,mouseButton));
    }
    public static void wheel(int x,int y,int delta){if(ready()&&drags.size()<24)drags.add(new int[]{x,y,0,-delta*30,delta});}
    public static void gesture(int x,int y,int dx,int dy){
        if(ready()&&drags.size()<24)drags.add(new int[]{x,y,Math.max(-100,Math.min(100,dx)),Math.max(-100,Math.min(100,dy))});
    }
    private static boolean scrollRoot(int id,int x,int y,int originX,int originY,int delta){
        return id>=0&&id<RSInterface.interfaceCache.length&&MobileUi.scroll(RSInterface.interfaceCache[id],originX,originY,x,y,delta,0);
    }
    private static void applyGesture(int[] d){
        if(game.menuOpen)return;int x=d[0],y=d[1],delta=-d[3];
        if(x>=0&&y>=0&&x<515&&y<340){
            if(game.openInterfaceID!=-1){scrollRoot(game.openInterfaceID,x,y,4,4,delta);game.inputTaken=true;return;}
            if(d.length>4){game.changeCameraZoom(d[4]);}
            else if(Math.abs(d[2])>=Math.abs(d[3])){game.minimapInt1=(game.minimapInt1+d[2]*3)&2047;game.idleTime=0;}
        }else if(x>=553&&y>=205&&y<466){
            int id=game.invOverlayInterfaceID!=-1?game.invOverlayInterfaceID:game.tabInterfaceIDs[game.tabID];
            if(scrollRoot(id,x,y,553,205,delta))game.needDrawTabArea=true;
        }else if(x>=17&&x<496&&y>=357&&y<434&&game.backDialogID==-1){
            game.anInt1089=Math.max(0,Math.min(Math.max(0,game.anInt1211-77),game.anInt1089+d[3]));game.inputTaken=true;
        }
    }
    public static void turn(int delta){if(ready()){game.minimapInt1=(game.minimapInt1+delta)&2047;game.idleTime=0;}}
    public static void zoom(int delta){if(ready())game.changeCameraZoom(delta);}
    public static void type(String text){
        if(!ready()||text==null||text.length()>100)return;
        for(char c:text.toCharArray())if(c>=32&&c<127)game.keyPressed(new KeyEvent(game,KeyEvent.KEY_PRESSED,System.currentTimeMillis(),0,KeyEvent.VK_UNDEFINED,c));
        game.keyPressed(new KeyEvent(game,KeyEvent.KEY_PRESSED,System.currentTimeMillis(),0,KeyEvent.VK_ENTER,'\n'));
    }
}