WebGL改造笔记
Posted stalendp
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WebGL改造笔记相关的知识,希望对你有一定的参考价值。
这段时间需要把原有的一个老项目改造成WebGL版本,遇到了一些困难,这里将记录改造的一些情况。
用Node.js来管理游戏内容
var express = require('express');
var app = express();
app.get('/', function (req, res)
res.send('Hello World!');
);
app.use(express.static('tttt'));
var server = app.listen(8080, function ()
var host = server.address().address;
var port = server.address().port;
console.log('Example app listening at http://%s:%s', host, port);
);
下面是webSocket的通信相关。
由于安全性问题,WebGL不支持TCPSocket,但是支持WebSockets;下面是几个socket的写法。
TCP Socket,用node.js运行:
var net = require('net');
var HOST = 'ipaddr';
var PORT = 123;
var b64encode = data => Buffer.from(data).toString('base64');
var b64decode = data => Buffer.from(data, 'base64');
var login1 = "MwAAAAEAAAAHAAAAMTA5NzU5AAIAAAA5ABEAAAA5ZmYzZjA1MzcyOWQ0ZmE0AAEAAAAA";
var login2 = "sgAAACMAAABJAAAAAQYAMTA5NzU5NpZHUC/B+SHjMCVg5U/R0BQzxFqpNRyv0JlnhMMzBXK+x7nT6RiAuuxrijfvanzYHySvXnCPToRHuenl1t/k8iEAAAA0NTY5MjcxRkM2REMyOTJBNUMwNzQxOTcwREMwQjk3OAA0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==";
var client = new net.Socket();
client.connect(PORT, HOST, function()
console.log('CONNECTED TO: ' + HOST + ':' + PORT);
// Write a message to the socket as soon as the client is connected, the server will receive it as message from the client
client.write(b64decode(login1));
client.write(b64decode(login2));
);
// Add a 'data' event handler for the client socket
// data is what the server sent to this socket
client.on('data', function(data)
console.log('DATA: ' + b64encode(data));
// Close the client socket completely
client.destroy();
);
// Add a 'close' event handler for the client socket
client.on('close', function()
console.log('Connection closed');
);
WebSocket, 运行在浏览器里面:
hello websocket!! Please see console to check the result!
<script>
(function(r)if(typeof exports==="object"&&typeof module!=="undefined")module.exports=r()else if(typeof define==="function"&&define.amd)define([],r)elsevar e;if(typeof window!=="undefined")e=windowelse if(typeof global!=="undefined")e=globalelse if(typeof self!=="undefined")e=selfelsee=thise.base64js=r())(function()var r,e,n;return function()function r(e,n,t)function o(i,a)if(!n[i])if(!e[i])var u=typeof require=="function"&&require;if(!a&&u)return u(i,!0);if(f)return f(i,!0);var d=new Error("Cannot find module '"+i+"'");throw d.code="MODULE_NOT_FOUND",dvar c=n[i]=exports:;e[i][0].call(c.exports,function(r)var n=e[i][1][r];return o(n?n:r),c,c.exports,r,e,n,t)return n[i].exportsvar f=typeof require=="function"&&require;for(var i=0;i<t.length;i++)o(t[i]);return oreturn r()("/":[function(r,e,n)"use strict";n.byteLength=c;n.toByteArray=v;n.fromByteArray=s;var t=[];var o=[];var f=typeof Uint8Array!=="undefined"?Uint8Array:Array;var i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";for(var a=0,u=i.length;a<u;++a)t[a]=i[a];o[i.charCodeAt(a)]=ao["-".charCodeAt(0)]=62;o["_".charCodeAt(0)]=63;function d(r)var e=r.length;if(e%4>0)throw new Error("Invalid string. Length must be a multiple of 4")return r[e-2]==="="?2:r[e-1]==="="?1:0function c(r)return r.length*3/4-d(r)function v(r)var e,n,t,i,a;var u=r.length;i=d(r);a=new f(u*3/4-i);n=i>0?u-4:u;var c=0;for(e=0;e<n;e+=4)t=o[r.charCodeAt(e)]<<18|o[r.charCodeAt(e+1)]<<12|o[r.charCodeAt(e+2)]<<6|o[r.charCodeAt(e+3)];a[c++]=t>>16&255;a[c++]=t>>8&255;a[c++]=t&255if(i===2)t=o[r.charCodeAt(e)]<<2|o[r.charCodeAt(e+1)]>>4;a[c++]=t&255else if(i===1)t=o[r.charCodeAt(e)]<<10|o[r.charCodeAt(e+1)]<<4|o[r.charCodeAt(e+2)]>>2;a[c++]=t>>8&255;a[c++]=t&255return afunction l(r)return t[r>>18&63]+t[r>>12&63]+t[r>>6&63]+t[r&63]function h(r,e,n)var t;var o=[];for(var f=e;f<n;f+=3)t=(r[f]<<16&16711680)+(r[f+1]<<8&65280)+(r[f+2]&255);o.push(l(t))return o.join("")function s(r)var e;var n=r.length;var o=n%3;var f="";var i=[];var a=16383;for(var u=0,d=n-o;u<d;u+=a)i.push(h(r,u,u+a>d?d:u+a))if(o===1)e=r[n-1];f+=t[e>>2];f+=t[e<<4&63];f+="=="else if(o===2)e=(r[n-2]<<8)+r[n-1];f+=t[e>>10];f+=t[e>>4&63];f+=t[e<<2&63];f+="="i.push(f);return i.join(""),],,[])("/"));
// ===================================================================
var b64encode = data => base64js.fromByteArray(data);
var b64decode = data => base64js.toByteArray(data);
var login1 = "MwAAAAEAAAAHAAAAMTA5NzU5AAIAAAA5ABEAAAA5ZmYzZjA1MzcyOWQ0ZmE0AAEAAAAA";
var login2 = "sgAAACMAAABJAAAAAQYAMTA5NzU5NpZHUC/B+SHjMCVg5U/R0BQzxFqpNRyv0JlnhMMzBXK+x7nT6RiAuuxrijfvanzYHySvXnCPToRHuenl1t/k8iEAAAA0NTY5MjcxRkM2REMyOTJBNUMwNzQxOTcwREMwQjk3OAA0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==";
var addr = 'ws://127.0.0.1:811';
var ws = new WebSocket(addr);
ws.onopen = function()
console.log('Connected to: ' + addr);
console.log('Try to login!!!');
ws.send(b64decode(login1));
ws.send(b64decode(login2));
ws.addEventListener("message", function(event)
console.log('Chrome Received: ' + b64encode(event.data));
alert("Login OK!!");
);
</script>
webSocket Server,用Node.js运行:
const WebSocket = require('ws');
const wss = new WebSocket.Server( port: 811 );
wss.on('connection', function connection(ws)
ws.on('message', function incoming(msg)
console.log('received: %s', msg);
setInterval(() =>
ws.send(msg);
, 1500);
);
);
C# 端的TCP socket例子:
string serverIP = "192.168.1.1";
int port = 12345;
Socket clientSocket = null;
private IEnumerator oldSendLogin()
Debug.Log("try to connect!!");
clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
clientSocket.Blocking = true;
var address = new IPEndPoint(IPAddress.Parse(serverIP), port);
IAsyncResult result = clientSocket.BeginConnect(address, null, null);
bool success = result.AsyncWaitHandle.WaitOne(5000);
if (success)
clientSocket.EndConnect(result);
clientSocket.Blocking = false;
yield return StartCoroutine(trySocketSend());
yield return StartCoroutine(trySocketReceive());
string login_param1 = "MwAAAAEAAAAHAAAAMTA5NzU5AAIAAAA5ABEAAAA5ZmYzZjA1MzcyOWQ0ZmE0AAEAAAAA";
string login_param2 = "sgAAACMAAABJAAAAAQYAMTA5NzU5NpZHUC/B+SHjMCVg5U/R0BQzxFqpNRyv0JlnhMMzBXK+x7nT6RiAuuxrijfvanzYHySvXnCPToRHuenl1t/k8iEAAAA0NTY5MjcxRkM2REMyOTJBNUMwNzQxOTcwREMwQjk3OAA0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==";
private bool isSended = false;
IEnumerator trySocketSend()
Debug.Log(">>>>>>> try socketSend!!!!");
while (true && !isSended)
yield return null;
var ret = clientSocket.Poll(0, SelectMode.SelectWrite);
if (ret)
var buff = Convert.FromBase64String(login_param1);
int n = clientSocket.Send(buff, 0, buff.Length, SocketFlags.None);
Debug.Log("Send Data Byte: " + n);
break;
while (true && !isSended)
yield return null;
var ret = clientSocket.Poll(0, SelectMode.SelectWrite);
if (ret)
var buff = Convert.FromBase64String(login_param2);
int n = clientSocket.Send(buff, 0, buff.Length, SocketFlags.None);
Debug.Log("Send Data Byte: " + n);
break;
isSended = true;
IEnumerator trySocketReceive()
Debug.Log(">>>>>>> try trySocketReceive!!!!");
while (true)
yield return null;
var ret = clientSocket.Poll(0, SelectMode.SelectRead);
if (ret)
var recvStream = new MemoryStream(64 * 1024);
var n = clientSocket.Receive(recvStream.GetBuffer(), (int)recvStream.Position, 64 * 1024, SocketFlags.None);
Debug.Log("Receive Data Byte: " + n);
C#端WebSocket的登陆逻辑,使用插件:Simple Web Sockets for Unity WebGL
public IEnumerator webSocketLogin()
var login1 = Convert.FromBase64String(login_param1);
var login2 = Convert.FromBase64String(login_param2);
WebSocket w = new WebSocket(new Uri("ws://192.168.1.1:1234"));
yield return StartCoroutine(w.Connect());
w.Send(login1);
w.Send(login2);
int i = 0;
while (true)
var reply = w.Recv();
if (reply != null)
Debug.LogFormat("Received: 0 ==> 1", reply.Length, Convert.ToBase64String(reply));
// w.SendString("Hi there" + i++);
if (w.error != null)
Debug.LogError("Error: " + w.error);
break;
yield return 0;
w.Close();
一个带CORS和https功能的server
var path = require('path');
var express = require('express');
var fs = require('fs');
var http = require('http');
var https = require('https');
var privateKey = fs.readFileSync('key.pem', 'utf8');
var certificate = fs.readFileSync('cert.pem', 'utf8');
var app = express();
app.get('/', function (req, res)
res.send('<a href="/index.html">Enter Game</a>');
);
app.use(express.static(
path.join('.', "WebBuild"),
setHeaders: (res) =>
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Credentials", "*");
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS, PUT");
res.setHeader("Access-Control-Allow-Headers", "Content-Type,Accept, X-Access-Token, X-Application-Name, X-Request-Sent-Time");
))
var credentials = key: privateKey, cert: certificate;
// your express configuration here
var httpServer = http.createServer(app);
var httpsServer = https.createServer(credentials, app);
httpServer.listen(8080);
httpsServer.listen(8443);
console.log(`Server Started, http on 8080, https on 8443`);
一个webSocket转socket的服务:
const net = require('net');
const fs = require('fs');
const https = require('https');
const WebSocket = require('ws');
// ============ proxy服务器地址 ===============
var HOST = 'xxxxxx';
var PORT = 123;
var WS_PORT = 811; // webSocket 的监听端口
var SSL_CERT = "./cert.pem";
var SSL_KEY = "./key.pem";
// ============ proxy服务器地址 ===============
var port = parseInt(process.argv[2]);
if(port>0)
WS_PORT = port;
else
console.log(`port is not set or not a number, use default $WS_PORT`);
var b64encode = data => Buffer.from(data).toString('base64');
var b64decode = data => Buffer.from(data, 'base64');
// 日志相关
var curDay = -1;
Log = msg =>
var date = new Date();
var hour = date.getHours();
var min = date.getMinutes();
var sec = date.getSeconds();
var mi = date.getMilliseconds();
var rt = `[$hour >= 10 ? hour : "0" + hour:$min >= 10 ? min : "0" + min:$sec >= 10 ? sec : "0" + sec $mi >= 100 ? mi : ((mi >= 10 ? "0" : "00") + mi)]`;
var day = date.getDate();
if(curDay != day) // 隔天,要显示日期信息
curDay = day;
var year = date.getFullYear();
var month = date.getMonth() + 1;
rt = `************** $year-$month >= 10 ? month : "0" + month-$day >= 10 ? day : "0" + day *****************\\r\\n` + rt;
console.log(`$rt $msg`);
// ============ 下面是TcpSocket,辅助连接Proxy服务器和客户端 ===========
// referTo https://nodejs.org/api/net.html
var TcpSocket = function()
var _userId = 0;
var _wsocket = null;
var _socket = null;
var _pendingSend = null;
var _attachCnt = 0;
var _alive = false;
// 进行连接
function init()
_alive = false;
_socket = new net.Socket();
_socket.on("connect", () =>
_alive = true;
if(_pendingSend!=null) // 处理链接期间到来的数据
while(_pendingSend.length > 0)
_socket.write(_pendingSend.shift()); // TODO 判断状态,并进行异常处理
);
_socket.on('data', data =>
if(_wsocket!=null && _wsocket.readyState === WebSocket.OPEN)
_wsocket.send(data);
);
_socket.on('close', had_err =>
_alive = false;
);
_socket.on('error', err =>
console.log("Error :: " + err);
);
;
init();
var _close = () =>
_attachCnt--;
if(_attachCnt<=0)
if(_socket!=null)
_socket.end(); // 通知服务器关闭socket
_socket = null;
if(_wsocket!=null)
_wsocket.close();
_wsocket = null;
if(tcpDict[_userId]!=null)
delete tcpDict[_userId];
;
var _trySend = data =>
if(_socket == null)
return;
if(_alive)
_socket.write(data); //TODO 进行异常处理
else
if(!_socket.connecting) // 尝试恢复连接
_socket.connect(PORT, HOST);
if(_pendingSend == null)
_pendingSend = [];
if(_pendingSend.length < 10) // 10条之内的消息,做缓存
_pendingSend.push(data);
else
console.log("cache is full!!");
;
return
close : _close,
send : _trySend,
get uid()
return _userId;
,
attach: (ws, uid) =>
_attachCnt++;
if(_wsocket!=null)
_wsocket.terminate();
_wsocket = ws;
_userId = uid;
if(_socket == null)
init();
if(!_alive && !_socket.connecting)
_socket.connect(PORT, HOST);
;
var tcpDict = ;
// ============ 下面是WebSocket,负责和客户端连接 ================
// https://github.com/websockets/ws
var idReg = /\\/(\\d+)/;
const server = new https.createServer(
cert: fs.readFileSync(SSL_CERT),
key: fs.readFileSync(SSL_KEY)
);
var wss = new WebSocket.Server( server );
wss.on('connection', (ws, req) =>
var uid = parseInt(req.url.replace(idReg, "$1"));
Log(`$wss.clients.size @ <$uid> $req.connection.remoteAddress`); // Connected!
if(uid <= 0) // uid is not correct!
console.log("userid is not correct!!!");
ws.terminate();
return;
var tcp = tcpDict[uid];
if(tcp==null)
tcp = new TcpSocket();
tcpDict[uid] = tcp;
tcp.attach(ws, uid);
ws.on('message', msg =>
tcp.send(msg);
);
ws.on("close", () =>
tcp.close();
Log(`$wss.clients.size ~ <$tcp.uid> $req.connection.remoteAddress`); // Disconnect
);
);
server.listen(WS_PORT);
Log(`WebSocket Server listen on : $WS_PORT`);
===================下面是浏览器中相关编程 ==========================
从网路下载文本的方式
var url = "https://192.168.1.194:8443/StreamingAssets/AssetsBundles/LocalBundleMap.txt";
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
// https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType
xhr.responseType = 'json';
xhr.onload = function (evt)
if (xhr.status == 200)
var json = xhr.response;
if (json)
console.log(json);
else
console.error("error:", xhr.status);
;
xhr.send();
var url = "https://192.168.1.194:8443/StreamingAssets/AssetsBundles/LocalBundleMap.txt";
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
// https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType
xhr.responseType = 'blob';
xhr.onload = function (evt)
if (xhr.status == 200)
var val = xhr.response;
if (val)
var reader = new FileReader();
reader.addEventListener("loadend", function()
console.log(reader.result);
);
reader.readAsText(val); // 读取成text
else
console.error("Error: ", xhr.status);
;
xhr.send();
IndexDB相关操作
参考:https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Using_IndexedDB
// md5 function
!function (n) "use strict"; function t(n, t) var r = (65535 & n) + (65535 & t); return (n >> 16) + (t >> 16) + (r >> 16) << 16 | 65535 & r function r(n, t) return n << t | n >>> 32 - t function e(n, e, o, u, c, f) return t(r(t(t(e, n), t(u, f)), c), o) function o(n, t, r, o, u, c, f) return e(t & r | ~t & o, n, t, u, c, f) function u(n, t, r, o, u, c, f) return e(t & o | r & ~o, n, t, u, c, f) function c(n, t, r, o, u, c, f) return e(t ^ r ^ o, n, t, u, c, f) function f(n, t, r, o, u, c, f) return e(r ^ (t | ~o), n, t, u, c, f) function i(n, r) n[r >> 5] |= 128 << r % 32, n[14 + (r + 64 >>> 9 << 4)] = r; var e, i, a, d, h, l = 1732584193, g = -271733879, v = -1732584194, m = 271733878; for (e = 0; e < n.length; e += 16)i = l, a = g, d = v, h = m, g = f(g = f(g = f(g = f(g = c(g = c(g = c(g = c(g = u(g = u(g = u(g = u(g = o(g = o(g = o(g = o(g, v = o(v, m = o(m, l = o(l, g, v, m, n[e], 7, -680876936), g, v, n[e + 1], 12, -389564586), l, g, n[e + 2], 17, 606105819), m, l, n[e + 3], 22, -1044525330), v = o(v, m = o(m, l = o(l, g, v, m, n[e + 4], 7, -176418897), g, v, n[e + 5], 12, 1200080426), l, g, n[e + 6], 17, -1473231341), m, l, n[e + 7], 22, -45705983), v = o(v, m = o(m, l = o(l, g, v, m, n[e + 8], 7, 1770035416), g, v, n[e + 9], 12, -1958414417), l, g, n[e + 10], 17, -42063), m, l, n[e + 11], 22, -1990404162), v = o(v, m = o(m, l = o(l, g, v, m, n[e + 12], 7, 1804603682), g, v, n[e + 13], 12, -40341101), l, g, n[e + 14], 17, -1502002290), m, l, n[e + 15], 22, 1236535329), v = u(v, m = u(m, l = u(l, g, v, m, n[e + 1], 5, -165796510), g, v, n[e + 6], 9, -1069501632), l, g, n[e + 11], 14, 643717713), m, l, n[e], 20, -373897302), v = u(v, m = u(m, l = u(l, g, v, m, n[e + 5], 5, -701558691), g, v, n[e + 10], 9, 38016083), l, g, n[e + 15], 14, -660478335), m, l, n[e + 4], 20, -405537848), v = u(v, m = u(m, l = u(l, g, v, m, n[e + 9], 5, 568446438), g, v, n[e + 14], 9, -1019803690), l, g, n[e + 3], 14, -187363961), m, l, n[e + 8], 20, 1163531501), v = u(v, m = u(m, l = u(l, g, v, m, n[e + 13], 5, -1444681467), g, v, n[e + 2], 9, -51403784), l, g, n[e + 7], 14, 1735328473), m, l, n[e + 12], 20, -1926607734), v = c(v, m = c(m, l = c(l, g, v, m, n[e + 5], 4, -378558), g, v, n[e + 8], 11, -2022574463), l, g, n[e + 11], 16, 1839030562), m, l, n[e + 14], 23, -35309556), v = c(v, m = c(m, l = c(l, g, v, m, n[e + 1], 4, -1530992060), g, v, n[e + 4], 11, 1272893353), l, g, n[e + 7], 16, -155497632), m, l, n[e + 10], 23, -1094730640), v = c(v, m = c(m, l = c(l, g, v, m, n[e + 13], 4, 681279174), g, v, n[e], 11, -358537222), l, g, n[e + 3], 16, -722521979), m, l, n[e + 6], 23, 76029189), v = c(v, m = c(m, l = c(l, g, v, m, n[e + 9], 4, -640364487), g, v, n[e + 12], 11, -421815835), l, g, n[e + 15], 16, 530742520), m, l, n[e + 2], 23, -995338651), v = f(v, m = f(m, l = f(l, g, v, m, n[e], 6, -198630844), g, v, n[e + 7], 10, 1126891415), l, g, n[e + 14], 15, -1416354905), m, l, n[e + 5], 21, -57434055), v = f(v, m = f(m, l = f(l, g, v, m, n[e + 12], 6, 1700485571), g, v, n[e + 3], 10, -1894986606), l, g, n[e + 10], 15, -1051523), m, l, n[e + 1], 21, -2054922799), v = f(v, m = f(m, l = f(l, g, v, m, n[e + 8], 6, 1873313359), g, v, n[e + 15], 10, -30611744), l, g, n[e + 6], 15, -1560198380), m, l, n[e + 13], 21, 1309151649), v = f(v, m = f(m, l = f(l, g, v, m, n[e + 4], 6, -145523070), g, v, n[e + 11], 10, -1120210379), l, g, n[e + 2], 15, 718787259), m, l, n[e + 9], 21, -343485551), l = t(l, i), g = t(g, a), v = t(v, d), m = t(m, h); return [l, g, v, m] function a(n) var t, r = "", e = 32 * n.length; for (t = 0; t < e; t += 8)r += String.fromCharCode(n[t >> 5] >>> t % 32 & 255); return r function d(n) var t, r = []; for (r[(n.length >> 2) - 1] = void 0, t = 0; t < r.length; t += 1)r[t] = 0; var e = 8 * n.length; for (t = 0; t < e; t += 8)r[t >> 5] |= (255 & n.charCodeAt(t / 8)) << t % 32; return r function h(n) return a(i(d(n), 8 * n.length)) function l(n, t) var r, e, o = d(n), u = [], c = []; for (u[15] = c[15] = void 0, o.length > 16 && (o = i(o, 8 * n.length)), r = 0; r < 16; r += 1)u[r] = 909522486 ^ o[r], c[r] = 1549556828 ^ o[r]; return e = i(u.concat(d(t)), 512 + 8 * t.length), a(i(c.concat(e), 640)) function g(n) var t, r, e = ""; for (r = 0; r < n.length; r += 1)t = n.charCodeAt(r), e += "0123456789abcdef".charAt(t >>> 4 & 15) + "0123456789abcdef".charAt(15 & t); return e function v(n) return unescape(encodeURIComponent(n)) function m(n) return h(v(n)) function p(n) return g(m(n)) function s(n, t) return l(v(n), v(t)) function C(n, t) return g(s(n, t)) function A(n, t, r) return t ? r ? s(t, n) : C(t, n) : r ? m(n) : p(n) "function" == typeof define && define.amd ? define(function () return A ) : "object" == typeof module && module.exports ? module.exports = A : n.md5 = A (this);
// In the following line, you should include the prefixes of implementations you want to test.
window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB || window.shimIndexedDB;
// DON'T use "var indexedDB = ..." if you're not in a function.
// Moreover, you may need references to some window.IDB* objects:
window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction || READ_WRITE: "readwrite" ; // This line should only be needed if it is needed to support the object's constants for older browsers
window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;
// (Mozilla has never prefixed these objects, so we don't need window.mozIDB*)
if (!window.indexedDB)
window.alert("Your browser doesn't support a stable version of IndexedDB. Such and such feature will not be available.");
else
console.log("the browser is OK!! --- ");
const DB_NAME = '/idbfs';
const DB_STORE = "FILE_DATA";
var db;
var req = window.indexedDB.open(DB_NAME);
var baseDir = `/idbfs/$md5(window.location.href.replace(/(https?.*)\\/[^\\/]*/, "$1"))`;
console.log(baseDir);
function bin2Str(array)
var result = "";
for (var i = 0; i < array.length; ++i)
result += (String.fromCharCode(array[i]));
return result;
req.onsuccess = function ()
// Better use "this" than "req" to the result to
// avoid problems with garbage collection
db = this.result;
var fn = `$baseDir/AssetsBundles/LocalBundleMap.txt`;
console.log("==> " + fn);
db.transaction(DB_STORE).objectStore(DB_STORE).get(fn).onsuccess = evt =>
var obj = evt.target.result;
var d = JSON.parse(bin2Str(obj.contents));
// console.log(JSON.stringify(d));
;
;
req.onerror = evt =>
console.error("Error openDB:", evt.target.errorCode);
;
req.onupgradeneeded = evt =>
console.log("openDb.onupgradeneeded");
// var store = evt.currentTarget.result.createObjectStore(
// DB_STORE, keyPath: 'id', autoIncrement: true );
// store.createIndex('title', 'title', unique: false );
;
javascript中的协程的用法:
参考:https://x.st/javascript-coroutines/
function coroutine(f)
var o = f(); // instantiate the coroutine
o.next(); // execute until the first yield
return function(x)
o.next(x);
var doJob = coroutine(function*()
console.log("init");
var x = yield;
console.log("First I got : " + x);
var y = yield;
console.log("Then I got: " + y);
);
doJob('a dog');
doJob('a cat');
JavaScript的枚举:
var JobStatus = Object.freeze(
UnInited:1,
DBReady:2,
BundleMapReady:3,
LocalResReady: 4,
);
Promise的用法 :
function get(url)
// Return a new promise.
return new Promise(function(resolve, reject)
// Do the usual XHR stuff
var req = new XMLHttpRequest();
req.open('GET', url);
req.onload = function()
// This is called even on 404 etc
// so check the status
if (req.status == 200)
// Resolve the promise with the response text
resolve(req.response);
else
// Otherwise reject with the status text
// which will hopefully be a meaningful error
reject(Error(req.statusText));
;
// Handle network errors
req.onerror = function()
reject(Error("Network Error"));
;
// Make the request
req.send();
);
//Now let's use it:
get('story.json').then(function(response)
console.log("Success!", response);
, function(error)
console.error("Failed!", error);
)
Promise的动态串联:
getJson('story.json').then(function (story)
addHtmlToPage(story.heading);
return story.chapterUrls.reduce(function (chain, chapterUrl)
// Once the last chapter's promise is done…
return chain.then(function ()
// …fetch the next chapter
return getJson(chapterUrl);
).then(function (chapter)
// and add it to the page
addHtmlToPage(chapter.html);
);
, Promise.resolve());
).then(function ()
// And we're all done!
addTextToPage("All done");
).catch(function (err)
// Catch any error that happened along the way
addTextToPage("Argh, broken: " + err.message);
).then(function ()
// Always hide the spinner
document.querySelector('.spinner').style.display = 'none';
);
async函数的基本写法
参考:点击打开链接
// async的写法:
async function logFetch(url)
try
const response = await fetch(url);
console.log(await response.text());
catch (err)
console.log('fetch failed', err);
// 相对于的promise的写法
function logFetch(url)
return fetch(url)
.then(response => response.text())
.then(text =>
console.log(text);
).catch(err =>
console.error('fetch failed', err);
);
批量下载例子:
参考:https://developers.google.com/web/fundamentals/primers/async-functions
In following examples, the URLs are fetched and read in parallel, but the "smart" reduce
bit is replaced with a standard, boring, readable for-loop.
// 方法1:
function logInOrder(urls)
// fetch all the URLs
const textPromises = urls.map(url =>
return fetch(url).then(response => response.text());
);
// log them in order
textPromises.reduce((chain, textPromise) =>
return chain.then(() => textPromise)
.then(text => console.log(text));
, Promise.resolve());
// 方法2:
async function logInOrder(urls)
// fetch all the URLs in parallel
const textPromises = urls.map(async url =>
const response = await fetch(url);
return response.text();
);
// log them in sequence
for (const textPromise of textPromises)
console.log(await textPromise);
================
C# 和 JavaScript的交互中的回调函数
参考: emscripten代码, emscripten文档 unity论坛 一个日文的文章 官方解决方案(SendMessage)
C#端:
// C#端对javascript的申明
[DllImport("__Internal")]
public static extern void callFuncStalendp(string strEx, System.Action<System.IntPtr> func);
// 回调函数
[MonoPInvokeCallback(typeof(System.Action))]
public static void callback(System.IntPtr ptr)
var val = Marshal.PtrToStringAuto(ptr);
Debug.LogError("The function is called!! " + val);
// 调用
FacebookHelper.callFuncStalendp("C#端", callback);
jslib端:
var LibraryFackbookHelper =
callFuncStalendp : function(msgEx, callback)
var msg = Pointer_stringify(msgEx);
var hello = "hello world! 你好!";
if (callback)
var stack = Runtime.stackSave();
Runtime.dynCall('vi', callback, [allocate(intArrayFromString(msg + hello), 'i8', ALLOC_STACK)]);
Runtime.stackRestore(stack);
;
mergeInto(LibraryManager.library, LibraryFackbookHelper);
关于Jslib的注意点,
var LibraryWonHelper =
$WonCommon:
str2Ptr : function(str)
return str && allocate(intArrayFromString(str), 'i8', ALLOC_STACK) || null;
,
invoke: function (callback, methodId, isOK, returnVal)
var stack = Runtime.stackSave();
Runtime.dynCall('viii', callback, [methodId, isOK, WonCommon.str2Ptr(returnVal)]);
Runtime.stackRestore(stack);
,
wbgl_won_login: function (wonId, callback) // TYPE 0
WonWrapper.login(Pointer_stringify(wonId)).then(function (id, token)
WonCommon.invoke(callback, 0, 1, JSON.stringify([id, token]));
).catch(function (err)
WonCommon.invoke(callback, 0, 0);
console.error(err);
);
,
wbgl_won_token: function ()
return WonCommon.str2Ptr(WonWrapper.getToken());
;
autoAddDeps(LibraryWonHelper, '$WonCommon');
mergeInto(LibraryManager.library, LibraryWonHelper);
函数的声明,
1. 都要使用function(...) 的形式,不能用 (param1, parram2) => 这种形式。
2. 导出的函数(在c#中 用[DllImport("__Internal")] 申明的),会在js代码中生成对应的函数(但是函数名前面加了"_")。比如wbgl_won_tokens生成的函数名是 _wbgl_won_tokens。这个代码是生成在mudule中的,在javascript不能够被直接调用。如果想直接调用,在合适的时机,把这些函数绑定到全局变量中。没有被导出的函数,是不会生成js代码的。
关于合适的时机,可以写一个函数,在unity启动的时候调用,并进行代码的注册。
3. jslib中的公用代码,参考上面例子中的 $WonCommon(注意要用autoAddDeps注册一下)
==============
Cookie的辅助类
let CookieHelper =
setCookie : (cname, cvalue, exdays) =>
let d = new Date();
d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
document.cookie = `$cname=$cvalue;expires=$d.toUTCString();path=/`;
,
getCookie : cname =>
return document.cookie.replace(new RegExp(`(?:(?:^|.*;\\\\s*)$cname\\\\s*=\\\\s*([^;]*).*$)|^.*$`, 'i'), "$1");
,
delCookie : cname =>
document.cookie = `$cname=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;
;
=============
异步加载类
let loadScript = (src, id) =>
return new Promise(function (resolve, reject)
if (document.getElementById(id))
reject("already loaded");
else
let s = document.createElement('script');
s.id = id;
s.src = src;
s.type = 'text/javascript';
s.onload = resolve;
s.onerror = reject;
document.head.appendChild(s);
);
===========
单例模式
var UnityLoader = UnityLoader || ....
以上是关于WebGL改造笔记的主要内容,如果未能解决你的问题,请参考以下文章