merge master

This commit is contained in:
trichimtrich 2019-04-23 03:36:31 +08:00
commit 79b0337ee8
20 changed files with 924 additions and 384 deletions

9
static/gameboy.html vendored
View file

@ -37,7 +37,8 @@
<div id="glass-gameboy-text">GAME BOY</div>
<div id="glass-color-text">C</div>
<div id="screen">
<video id="game-screen" autoplay=true poster="https://orig00.deviantart.net/cdcd/f/2017/276/a/a/october_2nd___gameboy_poltergeist_by_wanyo-dbpdmnd.gif">
<!--<video id="game-screen" autoplay=true poster="https://orig00.deviantart.net/cdcd/f/2017/276/a/a/october_2nd___gameboy_poltergeist_by_wanyo-dbpdmnd.gif">-->
<video id="game-screen" autoplay=true>
</video>
<div id="menu-screen">
@ -88,9 +89,9 @@
<br />
Game: <br />
Use Up, Down, Left, Right to Move <br />
Z to jump (A) <br />
X to sprint (B) <br />
C is start (in game) <br />
Z (A butotn) <br />
X (B button) <br />
C is start (or pause in some games) <br />
V is select game <br />
Q is super quit <br />
S to save <br />

View file

@ -13,7 +13,7 @@ textarea {
<button id="play" onclick="window.startGame()">Play</button>
<button id="play" onclick="pc.close()">Stop</button>
<button id="play" onclick="window.hihi()">Magic</button><br/><br/>
Your current room: <b><label id="currentRoomID" style="color:white"></b> <br />
Your current room: <b><label id="currentRoomID" style="color:blue"></b> <br />
You can join a remote game by roomID.<br />
Room ID: <input type="text" id="roomID">
Play as player(1,2): <select id="playerIndex">
@ -35,8 +35,8 @@ Play as player(1,2): <select id="playerIndex">
Player 1
Use Up, Down, Left, Right to Move <br />
Z to jump (A) <br />
X to sprint (B) <br />
Z to (A) <br />
X to (B) <br />
S to save <br />
L to load <br />
<!--Fullscreen media for better gaming experience<br /-->

1
static/js/const.js vendored
View file

@ -99,4 +99,5 @@ KEY_BIT = ["a", "b", "select", "start", "up", "down", "left", "right"];
INPUT_FPS = 100;
PINGPONGPS = 5;
INPUT_STATE_PACKET = 5;

View file

@ -3,23 +3,17 @@
function showMenuScreen() {
log("Clean up connection / frame");
// clean up before / after menu
try {
inputChannel.close();
} catch (err) {
log(`> [Warning] input channel: ${err}`);
}
//try {
//inputChannel.gameboyIndeoclose();
//} catch (err) {
//log(`> [Warning] peer connection: ${err}`);
//}
try {
pc.close();
} catch (err) {
log(`> [Warning] peer connection: ${err}`);
}
try {
conn.close();
} catch (err) {
log(`> [Warning] Websocket connection: ${err}`);
}
//try {
//conn.close();
//} catch (err) {
//log(`> [Warning] Websocket connection: ${err}`);
//}
$("#game-screen").hide();
if (!DEBUG) {
@ -69,7 +63,6 @@ function chooseGame(idx, force=false) {
function setState(e, bo) {
if (e.keyCode in KEY_MAP) {
keyState[KEY_MAP[e.keyCode]] = bo;
stateUnchange = false;
unchangePacket = INPUT_STATE_PACKET;
}
}
@ -90,7 +83,7 @@ document.body.onkeyup = function (e) {
}
} else if (screenState === "game") {
setState(e, false);
switch (KEY_MAP[e.keyCode]) {
case "save":
conn.send(JSON.stringify({"id": "save", "data": ""}));
@ -155,7 +148,7 @@ document.body.onkeydown = function (e) {
function sendInput() {
// prepare key
if (stateUnchange || unchangePacket > 0) {
if (unchangePacket > 0) {
st = "";
KEY_BIT.slice().reverse().forEach(elem => {
st += keyState[elem] ? 1 : 0;
@ -168,7 +161,6 @@ function sendInput() {
a[0] = ss;
inputChannel.send(a);
stateUnchange = false;
unchangePacket--;
}
}

3
static/js/global.js vendored
View file

@ -32,7 +32,6 @@ keyState = {
quit: false
}
stateUnchange = true;
unchangePacket = INPUT_STATE_PACKET;
inputTimer = null;
@ -53,4 +52,4 @@ function log(msg) {
document.getElementById('div').innerHTML += msg + '<br>'
console.log(msg);
}
}
}

168
static/js/ws.js vendored
View file

@ -1,69 +1,80 @@
var pc;
var curPacketID = "";
var curSessionID = "";
// web socket
function startGame() {
log("Starting game screen");
conn = new WebSocket(`ws://${location.host}/ws`);
// clear
endInput();
document.getElementById('div').innerHTML = "";
if (!DEBUG) {
$("#menu-screen").fadeOut(400, function() {
$("#game-screen").show();
});
// Clear old roomID
conn.onopen = () => {
log("WebSocket is opened. Send ping");
log("Send ping pong frequently")
// pingpongTimer = setInterval(sendPing, 1000 / PINGPONGPS)
startWebRTC();
}
conn.onerror = error => {
log(`Websocket error: ${error}`);
}
conn.onclose = () => {
log("Websocket closed");
}
conn.onmessage = e => {
d = JSON.parse(e.data);
switch (d["id"]) {
case "sdp":
log("Got remote sdp");
pc.setRemoteDescription(new RTCSessionDescription(JSON.parse(atob(d["data"]))));
//conn.send(JSON.stringify({"id": "sdpdon", "packet_id": d["packet_id"]}));
break;
case "requestOffer":
curPacketID = d["packet_id"];
log("Received request offer ", curPacketID)
startWebRTC();
//pc.createOffer({offerToReceiveVideo: true, offerToReceiveAudio: false}).then(d => {
//pc.setLocalDescription(d).catch(log);
//})
//case "sdpremote":
//log("Got remote sdp");
//pc.setRemoteDescription(new RTCSessionDescription(JSON.parse(atob(d["data"]))));
//conn.send(JSON.stringify({"id": "remotestart", "data": GAME_LIST[gameIdx].nes, "room_id": roomID.value, "player_index": parseInt(playerIndex.value, 10)}));inputTimer
//break;
case "heartbeat":
console.log("Ping: ", Date.now() - d["data"])
// TODO: Calc time
break;
case "start":
log("Got start");
roomID.value = ""
currentRoomID.innerText = d["room_id"]
break;
case "save":
log(`Got save response: ${d["data"]}`);
break;
case "load":
log(`Got load response: ${d["data"]}`);
break;
}
// end clear
}
conn = new WebSocket(`ws://${location.host}/ws`);
// Clear old roomID
conn.onopen = () => {
log("WebSocket is opened. Send ping");
conn.send(JSON.stringify({"id": "ping", "data": GAME_LIST[gameIdx].nes, "room_id": roomID.value, "player_index": parseInt(playerIndex.value, 10)}));
}
conn.onerror = error => {
log(`Websocket error: ${error}`);
}
conn.onclose = () => {
log("Websocket closed");
}
conn.onmessage = e => {
d = JSON.parse(e.data);
switch (d["id"]) {
case "pong":
log("Recv pong. Start webrtc");
startWebRTC();
break;
case "sdp":
log("Got remote sdp");
pc.setRemoteDescription(new RTCSessionDescription(JSON.parse(atob(d["data"]))));
break;
case "start":
log("Got start");
roomID.value = ""
currentRoomID.innerText = d["room_id"]
break;
case "save":
log(`Got save response: ${d["data"]}`);
break;
case "load":
log(`Got load response: ${d["data"]}`);
break;
}
}
function sendPing() {
// TODO: format the package with time
conn.send(JSON.stringify({"id": "heartbeat", "data": Date.now().toString()}));
}
function startWebRTC() {
// webrtc
pc = new RTCPeerConnection({iceServers: [{urls: 'stun:stun.l.google.com:19302'}]})
// input channel
inputChannel = pc.createDataChannel('foo')
// input channel, ordered + reliable
inputChannel = pc.createDataChannel('a', {
ordered: true,
});
inputChannel.onclose = () => log('inputChannel has closed');
inputChannel.onopen = () => log('inputChannel has opened');
inputChannel.onmessage = e => {
console.log(e);
log(`Message '${e.data}'`);
}
window.AudioContext = window.AudioContext || window.webkitAudioContext;
var context = new AudioContext();
@ -123,14 +134,11 @@ function startGame() {
}
}
pc.oniceconnectionstatechange = e => {
log(`iceConnectionState: ${pc.iceConnectionState}`);
if (pc.iceConnectionState === "connected") {
conn.send(JSON.stringify({"id": "start", "data": ""}));
startInput();
screenState = "game";
//conn.send(JSON.stringify({"id": "start", "data": ""}));
}
else if (pc.iceConnectionState === "disconnected") {
endInput();
@ -165,20 +173,38 @@ function startGame() {
session = btoa(JSON.stringify(pc.localDescription));
localSessionDescription = session;
log("Send SDP to remote peer");
conn.send(JSON.stringify({"id": "sdp", "data": session}));
// TODO: Fix curPacketID
conn.send(JSON.stringify({"id": "initwebrtc", "data": session, "packet_id": curPacketID}));
} else {
console.log(JSON.stringify(event.candidate));
}
}
function startWebRTC() {
// receiver only tracks
pc.addTransceiver('video', {'direction': 'recvonly'});
pc.addTransceiver('audio', {'direction': 'recvonly'});
// receiver only tracks
pc.addTransceiver('video', {'direction': 'recvonly'});
// create SDP
pc.createOffer({offerToReceiveVideo: true, offerToReceiveAudio: false}).then(d => {
pc.setLocalDescription(d).catch(log);
})
// create SDP
pc.createOffer({offerToReceiveVideo: true, offerToReceiveAudio: true}).then(d => {
pc.setLocalDescription(d).catch(log);
})
}
}
function startGame() {
log("Starting game screen");
screenState = "game";
conn.send(JSON.stringify({"id": "start", "data": GAME_LIST[gameIdx].nes, "room_id": roomID.value, "player_index": parseInt(playerIndex.value, 10)}));
// clear menu screen
endInput();
document.getElementById('div').innerHTML = "";
if (!DEBUG) {
$("#menu-screen").fadeOut(400, function() {
$("#game-screen").show();
});
}
// end clear
// startInput();
}