[英]Using SocketIO with Unity Quest 2 vr as client and Node.JS as server
我和我的團隊正在使用 C# 編寫的 Unity 為 Quest 2 構建 VR 游戲。
我們有一個程序是用 JavaScript (Node.JS) 編寫的服務器,它們的通信方式是通過 SocketIO。 在 Unity 編輯器中,兩個應用程序都可以相互通信,但是當我嘗試將應用程序構建為 APK 並將其加載到 Quest 2 時,服務器似乎無法與 VR 游戲通信。
關於我可以做些什么讓他們互相交談的任何建議? 這是我一直在使用的 NetworkManager 文件。
注意:文件中帶有 SocketIO 的任何內容下方總是有一條紅線,並顯示“找不到類型或命名空間名稱 'SocketIOCommunicator'(您是否缺少 using 指令或程序集引用?) [Assembly-CSharp]csharp(CS0246 )"
我不知道這意味着什么以及該怎么做。
using System;
using System.Collections;
using Firesplash.UnityAssets.SocketIO;
using Newtonsoft.Json;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using static PlayerManager;
using Classes.Managers;
namespace Network
{
public class JoinRoom
{
public string clinician;
}
public class StartGame
{
public string game;
}
public static class Pausing
{
public static Boolean isPaused = false;
}
public class Position
{
public float xPos;
public float zPos;
public float yPos;
}
[RequireComponent(typeof(SocketIOCommunicator))]
public class NetworkManager : MonoBehaviour
{
private SocketIOCommunicator _communicator;
private SocketIOInstance _socket;
[SerializeField] private TMP_InputField patientNameInput;
[SerializeField] private TextMeshProUGUI patientName;
[SerializeField] private TextMeshProUGUI clinicianName;
[SerializeField] private GameObject setName;
[SerializeField] private TextMeshProUGUI connText;
private void Awake()
{
DontDestroyOnLoad(this);
_communicator = GetComponent<SocketIOCommunicator>();
_socket = _communicator.Instance;
}
private void Start()
{
_socket.Connect();
HandleServerEvents();
StartCoroutine(PatientConnect());
}
private IEnumerator PatientConnect()
{
yield return new WaitUntil(() => _socket.IsConnected());
FetchName();
}
private void FetchName()
{
if (PlayerPrefs.HasKey("PatientName"))
{
PlayerPrefs.SetString("PatientName", "Test Subject FetchName()");
var name = PlayerPrefs.GetString("PatientName");
Debug.Log("Has Name: " + name);
_socket.Emit("unityConnect", name);
patientName.SetText(name);
SwitchToViewName();
}
else
{
SwitchToSetName();
}
}
private void HandleServerEvents()
{
_socket.On("userJoined", (string payload) =>
{
Debug.Log("Joined Room!");
var obj = JsonConvert.DeserializeObject<JoinRoom>(payload);
Debug.Log(obj.clinician);
clinicianName.SetText(obj.clinician);
connText.gameObject.SetActive(true);
});
_socket.On("startGame", (string payload) =>
{
Debug.Log("Started Game");
var obj = JsonConvert.DeserializeObject<StartGame>(payload);
Debug.Log(obj.game);
// connText.SetText("Started Planes");
switch(obj.game) {
case "3":
SceneManager.LoadScene("Planes");
break;
case "2":
SceneManager.LoadScene("Balloons");
break;
case "1":
SceneManager.LoadScene("Blocks");
break;
default:
SceneManager.LoadScene("Init");
break;
}
});
_socket.On("pauseGame", (string payload) => {
GameplayManager.getManager().ResumeGame();
Debug.Log("Unpaused");
});
_socket.On("resumeGame", (string payload) => {
GameplayManager.getManager().PauseGame();
Debug.Log("Paused");
});
_socket.On("updateClientPosition", (string payload) => {
Debug.Log(payload);
var obj = JsonConvert.DeserializeObject<Position>(payload);
float y = obj.yPos;
float x = obj.xPos;
float z = obj.zPos;
movePlayerX(x);
movePlayerY(y);
movePlayerZ(z);
});
_socket.On("kickPatient", (string payload) => {
Debug.Log(payload);
SceneManager.LoadScene("Init");
});
_socket.On("handMirror", (string payload) => {
Debug.Log(payload);
switch (payload) {
case "LEFT":
CalibrationManager.getManager().SetCalibrationType(2);
CalibrationManager.getManager().SetUnaffectedController(OVRInput.Controller.LTouch);
break;
case "RIGHT":
CalibrationManager.getManager().SetCalibrationType(2);
CalibrationManager.getManager().SetUnaffectedController(OVRInput.Controller.RTouch);
break;
default:
CalibrationManager.getManager().SetCalibrationType(0);
break;
}
});
}
private void OnDestroy()
{
_socket.Close();
}
public void SetPatientName()
{
PlayerPrefs.SetString("PatientName", patientNameInput.text);
FetchName();
}
public void SwitchToSetName()
{
setName.SetActive(true);
patientName.gameObject.SetActive(false);
}
private void SwitchToViewName()
{
setName.SetActive(false);
patientName.gameObject.SetActive(true);
}
}
}
這是JS服務器文件
import express, { json } from "express";
const app = express();
import cors from "cors";
import http from "http";
const httpServer = http.createServer(app);
import { Server, Socket } from "socket.io";
import "./database";
import {
addPatient,
checkUserWithPassword,
clearToken,
deleteSession,
getAllSessions,
getSessionsByUsername,
insertSession,
removePatientFromSession,
} from "./database";
import { ISession } from "./ Models/ISession";
import { logout, validateToken } from "./auth";
import { generateUniqueId } from "./utils";
import { IUser } from "./ Models/IUser";
const port = 5000;
interface IStartGame {
sessionKey: string;
game: string;
}
const io = new Server(httpServer, {
cors: {
origin: "http://localhost:3000",
methods: ["GET", "POST"],
},
});
io.use(async (socket, next) => {
const token = socket.handshake.headers.authorization;
// const session = socket.handshake.headers.session;
/*if (verifyToken(token)) {
setTimeout(next, 1000);
}*/
next();
});
app.use(cors());
app.use(express.json());
app.use((req, res, next) => setTimeout(next, 1000));
app.post("/login", async (req, res) => {
const params = req.body as IUser;
checkUserWithPassword(params.username, params.shaPassword).then((token) => {
if (token) {
res.send({ success: true, token });
} else {
res.send({ success: false });
}
});
});
app.post("/logout", async (req, res) => {
const token = req.headers.authorization;
logout(token, () => {
res.sendStatus(200);
});
});
app.post("/loginWithToken", (req, res) => {
const token = req.headers.authorization;
validateToken(token, (success: boolean, user: IUser) => {
if (success) {
res.send({
success: true,
user,
});
} else {
res.send({ success: false });
}
});
});
app.get("/sessions", (req, res) => {
const cred = req.body.user as IUser;
const token = req.headers.authorization;
validateToken(token, (success: boolean, user: IUser) => {
if (success) {
getAllSessions()
.then((sessions) => {
res.send({ sessions });
})
.catch(() => {
res.sendStatus(500);
});
} else {
res.sendStatus(403);
}
});
});
app.post("/session", (req, res) => {
const params = req.body as ISession;
const token = req.headers.authorization;
validateToken(token, (success: boolean, user: IUser) => {
if (success) {
getAllSessions().then((sessions: ISession[]) => {
const id = generateUniqueId(
5,
sessions.map((s) => s.sessionKey)
);
insertSession({
sessionName: params.sessionName,
sessionKey: id,
createdBy: user.username,
patients: [],
}).then((suc) => {
if (suc) {
res.send({ success: true });
} else {
res.sendStatus(500);
}
});
});
} else {
res.sendStatus(403);
}
});
});
app.delete("/sessionDelete", (req, res) => {
const params = req.body;
const token = req.headers.authorization;
validateToken(token, (success: boolean) => {
if (success) {
deleteSession(params.sessionKey);
console.log(`Clinicain deleted session ${params.sessionKey}`);
res.sendStatus(200);
} else {
res.sendStatus(403);
}
});
});
const unitySockets = {};
interface IUnitySocket {
name: string;
socket: Socket;
}
const addUnitySocket = (name: string, socket: Socket) => {
unitySockets[socket.id] = {
name,
socket,
};
};
io.on("connection", (socket) => {
console.log(`Client ${socket.id} has connected`);
socket.on("disconnect", () => {
if (unitySockets[socket.id]) {
unitySockets[socket.id].socket.disconnect();
delete unitySockets[socket.id];
}
console.log(`Client ${socket.id} has disconnected`);
});
socket.on("unityConnect", (name: string) => {
console.log(name + " joined unity");
socket.join("waiting");
addUnitySocket(name, socket);
});
socket.on("unityChangeName", (name: string) => {
if (unitySockets[socket.id]) {
unitySockets[socket.id].name = name;
} else {
addUnitySocket(name, socket);
}
});
app.post("/startGame", (req, res) => {
const params = req.body as IStartGame;
console.log(params.sessionKey);
console.log(params.game);
socket.to(params.sessionKey).emit("startGame", { game: params.game });
res.sendStatus(200);
});
app.patch("/pause", (req, res) => {
const params = req.body;
console.log("Clicked pause");
if (params.isPaused) {
socket.to(params.sessionKey).emit("resumeGame");
} else {
socket.to(params.sessionKey).emit("pauseGame");
}
res.sendStatus(200);
});
app.post("/updateClientPosition", (req, res) => {
const params = req.body;
console.log(params);
socket.to(params.sessionKey).emit("updateClientPosition", params.value);
res.sendStatus(200);
});
app.post("/handMirror", (req, res) => {
const params = req.body;
socket.to(params.sessionKey).emit("handMirror", params.hand);
res.sendStatus(200);
});
app.delete("/removePatientFromSession", (req, res) => {
const params = req.body;
const token = req.headers.authorization;
validateToken(token, (success: boolean) => {
if (success) {
removePatientFromSession(params.sessionKey, params.patientId);
console.log(`Clinician kicked user ${params.patientId}`);
socket.to(params.sessionKey).emit("kickPatient", params.patientId);
res.sendStatus(200);
} else {
res.sendStatus(403);
}
});
});
app.post("/leaveAllRooms", (req, res) => {
const rooms = io.sockets.adapter.sids[socket.id];
console.log(rooms);
// tslint:disable-next-line:forin
for (const r in rooms) {
socket.leave(r);
console.log("left room " + r);
}
res.sendStatus(200);
});
app.post("/join", (req, res) => {
const params = req.body as ISession;
socket.join(params.sessionKey);
console.log(`joined room ${params.sessionKey}`);
socket.to(params.sessionKey).emit("userJoined");
socket.emit("userJoined");
res.send({ success: true });
});
app.get("/getWaitingClients", (req, res) => {
const waitingSet = io.sockets.adapter.rooms.get("waiting");
const retList = [];
console.log(waitingSet);
if (!waitingSet) {
res.send({ waitingList: [] });
} else {
const waiting = Array.from(waitingSet);
waiting.forEach((val) => {
const unitySocket: IUnitySocket = unitySockets[val];
if (unitySocket) {
retList.push({
name: unitySocket.name,
socketId: val,
});
}
});
res.send({ waitingList: retList });
}
});
app.get("/getPatientsInSession", (req, res) => {
const roomKey = req.query.roomKey.toString();
console.log("Get room " + roomKey);
const roomSet = io.sockets.adapter.rooms.get(roomKey);
if (roomSet) {
const patients = Array.from(roomSet);
const retList = [];
patients.forEach((id) => {
if (unitySockets[id]) {
retList.push({
name: unitySockets[id].name,
socketId: id,
});
}
});
res.send({ patientList: retList });
} else {
res.send({ patientList: [] });
}
});
app.post("/addClientsToSession", (req, res) => {
const clientList = req.body.clientList;
const roomKey = req.body.roomKey;
const clinicianName = req.body.clinician;
console.log("Add to room " + roomKey);
clientList.forEach((id) => {
if (unitySockets[id].socket) {
unitySockets[id].socket.leave("waiting");
unitySockets[id].socket.join(roomKey);
unitySockets[id].socket.emit("userJoined", {
clinician: clinicianName,
});
}
});
addPatient(clientList, roomKey);
res.sendStatus(200);
});
app.post("/leave", (req, res) => {
const params = req.body as ISession;
socket.leave(params.sessionKey);
console.log(`left room ${params.sessionKey}`);
socket.to(params.sessionKey).emit("userLeft");
socket.emit("userLeft");
res.send({ success: true });
});
});
httpServer.listen(port, () => {
console.log(`server is listening on ${port}`);
});
Unity場景界面: Unity Scence
我找到了方法,我使用 heroku 來托管我的 node.js 服務器應用程序,然后不得不更改前端電子連接到 heroku 網站的方式。 統一任務游戲也是如此。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.