首页 > 解决方案 > Java 到虚拟现实

问题描述

我正在为 Java API 开发虚拟现实客户端

我无法从 Java Server-Socket 读取第二个命令(1 个字节顺序)。

这是我的java代码:

package de.e_nexus.vr.server;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;

import de.e_nexus.vr.server.codes.Client2ServerCode;
import de.e_nexus.vr.server.listeners.VRClientRequestAppInfo;
import de.e_nexus.vr.server.listeners.VRClientStatusListener;
import de.e_nexus.vr.server.listeners.VRExceptionListener;
import de.e_nexus.vr.server.mesh.Mesh;
import de.e_nexus.vr.server.mesh.MeshOutputStream;

public class VRServer extends ServerSocket {

    private static final Charset LATIN1;
    static {
        LATIN1 = Charset.forName("latin1");
    }
    private final Set<VRClientStatusListener> statusListeners = new LinkedHashSet<VRClientStatusListener>();
    private final Set<VRExceptionListener> exceptionListeners = new LinkedHashSet<VRExceptionListener>();
    private final Set<VRClientRequestAppInfo> infoListeners = new LinkedHashSet<VRClientRequestAppInfo>();

    private final Set<Mesh> toSend = new LinkedHashSet<Mesh>();

    private class Worker extends Thread {
        private boolean running = true;

        public void run() {
            try {
                setSoTimeout(50);
            } catch (SocketException e) {
                e.printStackTrace();
            }
            while (running) {
                cycle();
            }
            T = null;
        };

    }

    private Worker T;

    public VRServer() throws IOException {
        super(8779);
    }

    public void addVRClientStatusListener(VRClientStatusListener vrClientStatusListener) {
        statusListeners.add(vrClientStatusListener);
    }

    public void addVRExceptionListener(VRExceptionListener listener) {
        exceptionListeners.add(listener);
    }

    public void start() {
        if (T == null) {
            T = new Worker();
            T.start();
        }
    }

    public void stop() {
        T.running = false;
    }

    public boolean isStopping() {
        return T != null && !T.running;
    }

    protected void cycle() {
        try {
            Socket s = accept();
            log("Connected");
            InputStream in = s.getInputStream();
            OutputStream out = s.getOutputStream();
            int read = in.read();
            if (read == -1) {
                log("Closed unexpectedly "+in.available());
            } else {
                Client2ServerCode code = Client2ServerCode.read(read);
                log("Read " + code + " ord(" + read + ")");
                switch (code) {
                case GET_APP_INFO:
                    StringBuilder sb = new StringBuilder();
                    for (VRClientRequestAppInfo vrClientRequestAppInfo : infoListeners) {
                        sb.append(vrClientRequestAppInfo.getLatin1Title());
                    }

                    System.out.println(sb);
                    outLenString(out, sb.toString());
                    break;

                case GET_INCOMING_MESH:
                    int count = Math.min(toSend.size(), 100);
                    out.write(count);
                    System.out.println("wrote incomming mesah count");
                    for (int i = 0; i < count; i++) {
                        Iterator<Mesh> iterator = toSend.iterator();
                        Mesh mesh = iterator.next();
                        iterator.remove();
                        ByteArrayOutputStream buff = new ByteArrayOutputStream();
                        MeshOutputStream mos = new MeshOutputStream(buff);
                        mos.writeMesh(mesh);
                        mos.flush();
                        outLenString(out, buff.size() + "");
                        out.write(buff.toByteArray());
                    }
                    out.flush();
                default:
                    break;
                }
                System.out.println("Thanks");
            }
            s.close();
        } catch (Exception e) {
            notifyExceptionInCycle(e);
        }
    }

    private void log(String string) {
        System.out.println(string);
    }

    private void outLenString(OutputStream out, String string) throws IOException {
        byte[] b = string.getBytes(LATIN1);
        int length = b.length;
        out.write(length);
        out.write(b);
        out.flush();
    }

    private void notifyExceptionInCycle(Exception e) {
        boolean handled = false;
        for (VRExceptionListener vrExceptionListener : exceptionListeners) {
            try {
                vrExceptionListener.handle(e);
                handled = true;
            } catch (Exception ex) {
                ex.addSuppressed(e);
                ex.printStackTrace();
            }
        }

        if (!handled) {
            e.printStackTrace();
        }
    }

    public Thread getThread() {
        return T;
    }

    public void addInfoListener(VRClientRequestAppInfo l) {
        infoListeners.add(l);
    }

    public void addMesh(Mesh m) {
        toSend.add(m);
    }
}

Client2ServerCode 是这样的:

package de.e_nexus.vr.server.codes;

public enum Client2ServerCode {
    GET_APP_INFO, GET_INCOMING_MESH;

    public static Client2ServerCode read(int read) {
        for (Client2ServerCode c : values()) {
            if (c.ordinal() == read) {
                return c;
            }
        }
        return null;
    }
}

这是我的 AGK 基本代码

//******************************************************
// AGKVR Demo 1 - Castle Basic
//******************************************************
//This demo application will help you get to know AGKVR
SetErrorMode(0)
SetWindowTitle('VR')
//Load the AGKVR plugin
#import_plugin AGKVR

GET_APP_INFO as integer = 0

sock as integer
sock = ConnectSocket('127.0.0.1',8779,1000)

if sock = 0
    message ('Timeout while connecting!')
    end
endif

sleep(200)
if GetSocketConnected  (sock) <> 1 
    message ('Not connected!')
    end 
endif

rem connected!

SendSocketByte(sock, GET_APP_INFO)
FlushSocket(sock)
if GetSocketConnected  (sock) <> 1 
    message ('Could not request for app-info from server!')
    end 
endif

readTitle(sock)
DeleteSocket(sock)
sock = ConnectSocket('127.0.0.1',8779,1000)
if sock = 0
    message ('Timeout while connecting!')
    end
endif
readMesh(sock)
DeleteSocket(sock)
// <---------------------- below this is old example code, you can ignore it
//Init App

SetSyncRate(0, 0)
SetWindowSize( 1024, 768, 0 )
SetScissor(0, 0, 0, 0)

//Hand Model ID numbers
RightHandModel as integer = 100
LeftHandModel as integer = 101
HandModelImg as integer = 100

//Generate Mipmaps for nicer looking textures
SetGenerateMipmaps( 1 ) 

//Create Skybox
SetSkyBoxHorizonColor( 200, 200, 255 )
SetSkyBoxHorizonSize( 10, 2 )
SetSkyBoxSkyColor( 50, 50, 255)
SetSkyBoxSunColor( 255,255,255 )
SetSkyBoxVisible( 1 )
SetSkyBoxSunSize( 1, 3.0 )
SetSkyBoxSunVisible( 1 )

//Load Hand Models
//---------------------------
//Right Hand

LoadObjectWithChildren(RightHandModel,"RHand.FBX")
SetObjectScale(RightHandModel,1.15,1.15,1.15)
SetObjectPosition(RightHandModel,0.0,0.0,-0.07)
SetObjectRotation(RightHandModel,0.0,180.0,90.0)
FixObjectPivot(RightHandModel)
SetObjectAnimationSpeed(RightHandModel,20)
LoadImage(HandModelImg,"Hand.png")
SetObjectImage(RightHandModel,HandModelImg,0)
SetObjectVisible(RightHandModel,0)
SetObjectCollisionMode(RightHandModel,0)

//Left Hand
LoadObjectWithChildren(LeftHandModel,"LHand.FBX")
SetObjectScale(LeftHandModel,1.15,1.15,1.15)
SetObjectPosition(LeftHandModel,0.0,0.0,-0.07)
SetObjectRotation(LeftHandModel,0.0,180.0,270.0)
FixObjectPivot(LeftHandModel)
SetObjectAnimationSpeed(LeftHandModel,20)
SetObjectImage(LeftHandModel,HandModelImg,0)
SetObjectVisible(LeftHandModel,0)
SetObjectCollisionMode(LeftHandModel,0)

//Call function to load world models
LoadWorld( )

//Set the Camera Range in AGKVR
//It is necessary to use this command for setting the camera's range instead of the standard AGK SetCameraRange command
AGKVR.SetCameraRange( 0.01, 1000.0 )

//Initialiaze AGKVR
//------------------------------------------------
// The parameters are the Right and Left Eye image ID's that will be used to render to the HMD
InitError As Integer
RightEyeImg As Integer = 500
LeftEyeImg As Integer = 501
InitError = AGKVR.Init( RightEyeImg, LeftEyeImg )
// InitError = 0: SUCCESS!
// InitError = 1: Unable to init VR runtime
// InitError = 2: Compositor initialization failed.

//This command will lock the player's heading direction
//to follow the turn angle of the HMD. This would be common in FPS games, where
//you want the forward moving direction's turn angle to change based on where the
//player is looking. LockPlayerTurn is ON(1) by default
AGKVR.LockPlayerTurn( 1 )

//This command will lock the player's heading direction (forward on the Z axis)
//to follow the pitch angle of the HMD. This would be useful in a freeflight style game
//where you want the forward moving direction's pitch angle to change based on where the
//player is looking. LockPlayerPitch is OFF(0) by default
AGKVR.LockPlayerPitch( 0 )

CreateVector3(1,2,3.4)


do

    //Get AGKVR's Player container's current Position, which will be used later for collision purposes:
    PlayerPosX as float
    PlayerPosY as float
    PlayerPosZ as float
    PlayerPosX = AGKVR.GetPlayerX(): `
    PlayerPosY = AGKVR.GetPlayerY()
    PlayerPosZ = AGKVR.GetPlayerZ()

    //Control Player Turn Angle with Left Controller Joystick
    valx as float
    valz as float
    valx = AGKVR.LeftController_JoyX( )
    AGKVR.RotatePlayerLocalY( valx )

    //Control Player Movement based on Right Controller Joystick
    valx = AGKVR.RightController_JoyX( )
    valz = AGKVR.RightController_JoyY( )
    AGKVR.MovePlayerLocalZ( valz*0.06 )
    AGKVR.MovePlayerLocalX( valx*0.06 )

    //Move with the Keyboard
    if GetRawKeyState(87) = 1
        AGKVR.MovePlayerLocalZ( 0.1 )
    endif
    if GetRawKeyState(83) = 1
        AGKVR.MovePlayerLocalZ( -0.1 )
    endif
    if GetRawKeyState(65) = 1
        AGKVR.MovePlayerLocalX( -0.1 )
    endif
    if GetRawKeyState(68) = 1
        AGKVR.MovePlayerLocalX( 0.1 )
    endif

    //Collision
    New_PlayerPosX as float
    New_PlayerPosY as float
    New_PlayerPosZ as float
    //Get the Player's ground position now that any movement has occured.
    New_PlayerPosX = AGKVR.GetPlayerX()
    New_PlayerPosY = AGKVR.GetPlayerY()
    New_PlayerPosZ = AGKVR.GetPlayerZ()
    //Check for collision from previous position to new position (add the radius to the Y position)
    if ObjectSphereSlide(0,PlayerPosX,PlayerPosY+0.5,PlayerPosZ,New_PlayerPosX,New_PlayerPosY+0.5,New_PlayerPosZ,0.5)>0
        //Get the collision point (Subtract the collision radius from the Y position)
        New_PlayerPosX = GetObjectRayCastSlideX(0)
        New_PlayerPosY = GetObjectRayCastSlideY(0)-0.5
        New_PlayerPosZ = GetObjectRayCastSlideZ(0)
        //Set the player position to the collision point
        AGKVR.SetPlayerPosition( New_PlayerPosX, New_PlayerPosY, New_PlayerPosZ )
    endif

    //Control Hand animation based on Trigger feedback
    Rvalue as float
    Lvalue as float
    Rvalue = AGKVR.RightController_Trigger( )
    Lvalue = AGKVR.LeftController_Trigger( )
    SetObjectAnimationFrame(RightHandModel, GetObjectAnimationName( RightHandModel, 1 ), GetObjectAnimationDuration(RightHandModel,GetObjectAnimationName( RightHandModel, 1 ))*Rvalue,0)
    SetObjectAnimationFrame(LeftHandModel, GetObjectAnimationName( LeftHandModel, 1 ), GetObjectAnimationDuration(LeftHandModel,GetObjectAnimationName( LeftHandModel, 1 ))*Lvalue,0)

    //Now that the player's position and orientation has been modified,
    //the UpdatePlayer command is called to update all the components of
    //AGKVR's player framework
    AGKVR.UpdatePlayer( )

    //Position Hand Objects
    if  AGKVR.RightControllerFound( ) = 1
        SetObjectPosition( RightHandModel, AGKVR.GetRightHandX(), AGKVR.GetRightHandY(), AGKVR.GetRightHandZ())
        SetObjectRotation( RightHandModel, AGKVR.GetRightHandAngleX(), AGKVR.GetRightHandAngleY(), AGKVR.GetRightHandAngleZ())
        SetObjectVisible( RightHandModel, 1 )
    else
        SetObjectVisible( RightHandModel, 0 )
    endif

    if  AGKVR.LeftControllerFound( ) = 1
        SetObjectPosition( LeftHandModel, AGKVR.GetLeftHandX(), AGKVR.GetLeftHandY(), AGKVR.GetLeftHandZ())
        SetObjectRotation( LeftHandModel, AGKVR.GetLeftHandAngleX(), AGKVR.GetLeftHandAngleY(), AGKVR.GetLeftHandAngleZ())
        SetObjectVisible( LeftHandModel, 1 )
    else
        SetObjectVisible( LeftHandModel, 0 )
    endif

    //This command renders to the HMD.
    AGKVR.Render(  )


    //The camera's position and rotation will determine what is displayed on the monitor, not the HMD
    SetCameraPosition( 1, AGKVR.GetHMDX(), AGKVR.GetHMDY(), AGKVR.GetHMDZ())
    SetCameraRotation( 1, AGKVR.GetHMDAngleX(), AGKVR.GetHMDAngleY(), AGKVR.GetHMDAngleZ()) 


    Print( ScreenFPS() )


    //Display some controller feedbacks on the monitor
    if AGKVR.RightController_Grip() = 1
        Print( "Right Grip Pressed" )
    endif
     if AGKVR.LeftController_Grip() = 1
        Print( "Left Grip Pressed" )
    endif  
     if AGKVR.LeftController_Button1() = 1
        Print( "Left Button 1 Pressed" )
    endif   
      if AGKVR.RightController_Button1() = 1
        Print( "Right Button 1 Pressed" )
    endif 
     if AGKVR.LeftController_Button2() = 1
        Print( "Left Button 2 Pressed" )
    endif   
      if AGKVR.RightController_Button2() = 1
        Print( "Right Button 2 Pressed" )
    endif  

    //Sync to update the monitor display (the HMD display is updated through AGKVR's Render Command
    //so this Sync is not necessary to for rendering to the HMD)
    Sync()
loop

function readTitle(s)
    count as integer
    count=0
    sleep (5)
    while count < 100
        if GetSocketBytesAvailable(s) > 0 
            exit
        endif
        sleep(10)
        inc count
    endwhile
    if count = 100
        message ('Timeout while read title!')
        end
    endif
    appTitleLength as integer
    appTitleLength = GetSocketByte(s)
    txt as string
    txt=''
    for i = 0 to appTitleLength
        txt = txt + chr(GetSocketByte(s))
    next i
    SetWindowTitle(txt)
endfunction

function readMesh(s)
    if SendSocketByte(s, 1) = 1
        message('Could not place command to buffer')
        end
    endif
    if FlushSocket(s) = 1
        message('Could not send the buffered command to the server')
        end
    endif
    count as integer
    count = 0
    message('flushed')
    sleep (5)
    while count < 100
        if GetSocketBytesAvailable(s) > 0 
            exit
        endif
        sleep(4)
        inc count
    endwhile
    if count = 100
        message ('Timeout while read incomming mesh count!')
        end
    endif

    // in count is the mesh size stored.
    for i = 0 to count
        lenSize as integer
        count = 0
        while count < 100
            if GetSocketBytesAvailable(s) > 0
                exit
            endif
            sleep(5)
            inc count
        endwhile
        if count = 100
            message('Timeout while read size of incomming mesh memblock.')
            end
        endif
        lenSize = GetSocketByte(s)
        lenTxt as String
        lenTxt=''
        for j = 0 to lenSize
            lenTxt=lenTxt + chr(GetSocketByte(s))
        next j
        lenSize = val(lenTxt)
        count = 0
        while count < 100
            if GetSocketBytesAvailable(s) = lenSize
                exit
            endif
            sleep(5)
            inc count
        endwhile
        if count = 100
            message('Timeout while read incomming mesh memblock.')
            end
        endif
        blk as integer
        blk = CreateMemblock(lenSize)
        for j = 0 to lenSize
            SetMemblockByte(blk, j, GetSocketByte(s))
        next j
        CreateObjectFromMeshMemblock(blk)
    next i

endfunction

function LoadWorld(  )
    scaleval as float = 0.037

    LoadObject(1,"Castle.fbx")
    SetObjectScale(1,scaleval,scaleval,scaleval)

    LoadImage(1,"banquet hall_D.png")
    LoadImage(2,"portcullis_D.png")
    LoadImage(3,"stable_D.png")
    LoadImage(4,"well_D.png")
    LoadImage(5,"wall.png")
    LoadImage(6,"tower.png")
    LoadImage(7,"kings apartment_D.png")
    SetObjectMeshImage( 1, 1, 2, 0 )
    SetObjectMeshImage( 1, 2, 5, 0 )
    SetObjectMeshImage( 1, 4, 6, 0 )
    SetObjectMeshImage( 1, 5, 7, 0 )
    SetObjectMeshImage( 1, 6, 1, 0 )        
    SetObjectMeshImage( 1, 7, 3, 0 )    
    SetObjectMeshImage( 1, 8, 4, 0 )    
    SetObjectMeshImage( 1, 9, 1, 0 )

    //Field
    LoadImage(50,"TerrainGrass.png")
    LoadObject(50,"field.fbx")
    SetObjectRotation(50,0,0,0)
    SetObjectScale(50,5,5,5)
    SetObjectImage(50,50,0)
    SetObjectMeshUVScale( 50, 1, 0, 100, 100 )
    SetImageWrapU(50,1)
    SetImageWrapV(50,1)

endfunction

App-info 已成功读取,但 Java 没有收到第二个命令的第一个字节,为什么不呢?

标签: javasteamagk-basic

解决方案


不允许将套接字作为参数。我将打开的套接字放在函数内部并且它可以工作。


推荐阅读