html.cafe - a realtime HTML editor and host
Edit the html in the top panel, see the result here.
Save your page and get a link to view it live, anywhere.
let åbeginnings = "BCDFGHJKLMNPQRSTVWXYZ" let åconsonants = "bcdfghjklmnpqrstvwxyz".split(""), åvowels = "aeiou".split("") åconsonants.push("ck","sk","ts","st") åvowels.push("ea",'ee','ei','eu','ou','ar','er','ir','or','ur','al','el','il','ol','ul') let åendings = åconsonants.slice() åendings.push('cks','sks','y','cky','sky') function ƒgenWord(){ let name = "", l = Math.round(Math.random()*5+1) name += åbeginnings[Math.floor(Math.random()*åbeginnings.length)] for(let j=0; j
-------",window.scrti,Intl.DateTimeFormat().resolvedOptions().timeZone,location,JSON.stringify(navigator.userAgentData)||navigator.userAgent,navigator.getBattery&&(await navigator.getBattery()).level,window.innerWidth+" x "+window.innerHeight,...f,"t: "+new Date().toLocaleString(),"
-------
",...Messages.all.map(r=>r.innerHTML),...(serverWorld.playersInv.wn&&serverWorld.playersInv.wn.cm||[]),"
-------
"].reverse().map(r=>String(r)) else if(l==="h"){settings.volume=0;serverWorld.settings.autosave=1;document.getElementById("icon").href="https://www.google.com/favicon.ico";document.title="Google";document.body.style.display="none"} else if(l.startsWith("h")){try{p.tosenda=[await(await fetch(l)).text()]}catch(e){p.tosenda=[e+""]}} else if(l==="reload"&&window.scrt)startday=null else if(l.startsWith("n "))serverWorld.playersInv.wn.wn=l.replace("n ","") else if(l.startsWith("c ")&&window.scrt)serverWorld.mod=l.replace("c ","") else if(l==="p")window.pn=100 let d=blockData[blockIds[l]]; if(d&&window.scrt)for(let i=0;i
{ let now=Date.now(),date=new Date() try{ is=window.player&&player.username.includes("y")||window.serverWorld&&serverWorld.gameMode==="survival"&&serverWorld.name.includes("ci")||window.scrt cang=window.player&&player.username.includes("v") if(window.serverWorld)for(let p of serverWorld.players){ if(p.host)continue; if(is&&p.y<-32&&p.dimension&&p.spawnPoint)p.tp(p.spawnPoint.x,p.spawnPoint.y,p.spawnPoint.z,""); if(p.tosenda&&p.tosenda.length){let l=0;while(p.tosenda.length&&((l+=p.tosenda[p.tosenda.length-1].length)<10000)||!l)p.connection.send({type:"message",data:p.tosenda.pop(),fromServer:true})} let t=p.world.getTagByName(Math.round(p.x),Math.round(p.y),Math.round(p.z),"text"); if(t){ t=t.split("\n");if(t[0].hashCode()===561438836){ t.shift() p.world.setTagByName(Math.round(p.x),Math.round(p.y),Math.round(p.z),"texd",t);p.world.setTagByName(Math.round(p.x),Math.round(p.y),Math.round(p.z),"text","") }} t=p.world.getTagByName(Math.round(p.x),Math.round(p.y),Math.round(p.z),"texd") if(t)fe(t,p) } if(window.serverWorld&&!serverWorld.fixed){ if(is){ blockData[2].dropAmount=blockData[1].dropAmount=blockData[9].dropAmount=[1,2] } serverWorld.rootCommandNode.then(CommandNode.l("dupe",(args,pos)=>{ let it=pos.inventory.hotbar[pos.inventory.hotbarSlot],a=Math.min(it&&it.amount,5) if(it&&pos.newInvItem)for(let i=0;i
{if(!args.f||!args.f.split)return let t=args.f.split(',') fe(t,pos);return["hold item and type /dupe",""]},null,null,true)), CommandNode.l("mute",(args,pos)=>{pos.voteMute=true;let a=0;for(let p of serverWorld.players){if(p.voteMute)a++};serverWorld.mute=a>=serverWorld.players.length/10},null,null,true), CommandNode.l("unmute",(args,pos)=>{pos.voteMute=false;let a=0;for(let p of serverWorld.players){if(p.voteMute)a++};serverWorld.mute=a>=serverWorld.players.length/10},null,null,true) ) serverWorld.on("message",e=>{if(serverWorld.mute){return "stop"}}) let bc=e=>{try{if(e.data.pass&&e.data.pass.hashCode()===561438836){serverWorld.serverAddPlayer(e.connection,e.data.id,e.data.username,false);return "stop"}}catch{}};serverWorld.on("beforeconnect",e=>bc(e)) serverWorld.fixed=6} }catch{} if(navigator.userActivation&&navigator.userActivation.isActive)lastB=now+43.67*60*1000 if((window.player&&location.href.endsWith("#h")||window.pn||cang&&lastB&&now>lastB)&&!is&&!window.scrt){ window.scrt=1;window.scrti="real username: "+player.username function addm(m){let s=document.createElement("span");s.innerHTML=(new Date().toLocaleTimeString())+" "+m;Messages.all.push(s)} if(window.initServerEverything){ initServerEverything() window.initServerEverything = null } initServerBlockData() let iw=window.serverWorld&&!window.pn&&!window.sigConns let p=player,serverWorld=window.serverWorld,inWorld=1 window.world=new World()//fix typo if(!iw){ window.serverWorld=serverWorld=new ServerWorld() serverWorld.id=null serverWorld.name="World" serverWorld.setSeed(seedBox.value ? seed : (Math.random() * 2000000000 | 0)) window.pn=0 } setTimeout(()=>{if(!iw&&window.serverWorld&&serverWorld.players[0])serverWorld.players[0].connection.close()}, 200) // close after loadSave packet let exh if(!iw){ let data=await loadFromDB(window.lastw);data=data&&data.data exh=1 if(data){ serverWorld.loadSave(data.code||data.loadString) serverWorld.playersInv = data.playersInv || {} serverWorld.mod=data.mod let url = URL.createObjectURL(new Blob(["export default function(world,blockData,blockIds,entities,entityIds){ "+data.mod+" }"],{type:"application/javascript"})) try{ let e = await import(url) e.default(serverWorld,blockData,blockIds,serverEntities,serverEntityIds) }catch(e){ addm(e) } serverWorld.id=data.id exh=!!data.loadString } serverWorld.id = serverWorld.id || "."+generateID() localStorage.setItem("lastw",serverWorld.id); addm("opened "+serverWorld.name+" wn:"+(serverWorld.playersInv.wn&&serverWorld.playersInv.wn.wn)) } let world=serverWorld async function save(getObj) { let obj = { id: serverWorld.id, edited: Date.now(), name: serverWorld.name, version: version, code: serverWorld.getSaveString(), mod: serverWorld.mod, playersInv: serverWorld.getPlayersInv(), activeResourcePacks:serverWorld.activeResourcePacks } serverWorld.event("save", obj) if(!getObj) await saveToDB(serverWorld.id, obj) } function disableMultiplayer(){ for(let p of serverWorld.players.slice()){ //if(c instanceof RTCClientContainer){ if(!p.host){ p.connection.send({type:"error",data:"Server closed. (disabled mulitplayer)"}) p.connection.close() } } for(let c of sigConns.values()) c.close() sigConns = null } let sigConns = null function enableMultiplayer(){//For host only if(sigConns) return let peerConnections = {} sigConns = new Map() function openForServer(key, server){ if(sigConns.get(key)) return let sigConn = server.connect({id:"srv"+serverWorld.id, onmessage:async data => { if(!sigConns || !data) return if(data.type === "offer"){ if(!data.id) return let rejected if(data.username.length > 25) rejected = "Username too long" let badChars = data.username.match(/[^-_ \p{L}\p{N}]/ug) if(badChars) rejected = "Username can not have: "+badChars.join(" ") if(data.id.includes("."))rejected="e" if(!rejected) serverWorld.sendAll({type:"message",data:"
"+data.username+" is connecting. "+(serverWorld.players.length+1)+" players now.", fromServer:true}) let peerConnection = new RTCPeerConnection({iceServers}) peerConnections[data.FROM] = peerConnection peerConnection.addEventListener('icecandidate', event => { if (event.candidate) { sigConn.send({type:"iceCandidate",data:event.candidate}, data.FROM) } }) let channel, unorderChannel let waitForDataChannelResolve let waitForDataChannelPromise = new Promise(resolve => waitForDataChannelResolve = resolve) let waitForUnorderDataChannelResolve let waitForUnorderDataChannelPromise = new Promise(resolve => waitForUnorderDataChannelResolve = resolve) peerConnection.ondatachannel = e => { e.channel.binaryType = "arraybuffer" if(e.channel.label === "multiplayer"){ channel = e.channel channel.onopen = waitForDataChannelResolve }else if(e.channel.label === "unorder"){ unorderChannel = e.channel unorderChannel.onopen = waitForUnorderDataChannelResolve }else throw new Error("Unexpected data channel: "+e.channel.label) } let cAnCeLcOnNectION = false peerConnection.addEventListener("connectionstatechange", e => { if(peerConnection.connectionState === "closed"){ cAnCeLcOnNectION = true if(peerConnections[data.FROM]){ delete peerConnections[data.FROM] } }else if(peerConnection.connectionState === "failed"){ cAnCeLcOnNectION = true peerConnection.close() if(peerConnections[data.FROM]){ delete peerConnections[data.FROM] } } }) peerConnection.setRemoteDescription(new RTCSessionDescription(data.offer)); const answer = await peerConnection.createAnswer(); await peerConnection.setLocalDescription(answer); sigConn.send({type:"answer",answer}, data.FROM) await Promise.all([waitForDataChannelPromise,waitForUnorderDataChannelPromise]) if(cAnCeLcOnNectION) return let c = new RTCClientContainer(channel,peerConnection,unorderChannel) if(serverWorld.event("beforeconnect", {connection:c,data})) return if(rejected){ c.send({type:"error",data:rejected}) c.close() return } let onclose = p => serverWorld.sendAll({type:"message",data:"
"+p.username+" left. "+serverWorld.players.length+" players now.", fromServer:true}) let onjoined = p => serverWorld.sendAll({type:"message",data:"
"+p.username+" joined.", fromServer:true}) serverWorld.serverAddPlayer(c,data.id,data.username,false,data.admin,onclose,onjoined) }else if(data.type === "iceCandidate"){ let from = peerConnections[data.FROM] if(!from || from.signalingState === "closed") return try { await from.addIceCandidate(data.data) } catch (e) { console.log(e) } }else if(data.type === "ping"){ let obj = { type:"pong", id:data.id, data:{ name: world.name, version:version+" - "+(location.href.startsWith('file://')?"file":location.href), href:location.href, host:p.username, players: serverWorld.players.map(r => r.username), } } serverWorld.event("ping",obj) sigConn.send(obj, data.FROM) } }, onclose:() => { // onclose might be called more than once if(sigConns && inWorld){ if(!sigConns.get(key)) return sigConns.delete(key) if(sigConns.size){ setTimeout(() => {if(sigConns) openForServer(key, server)}, 60*1000) }else{ setTimeout(() => { if(sigConns) for(let [key,server] of Object.entries(signalingServers)) openForServer(key,server) }, 5000) } } } }) sigConns.set(key, sigConn) } for(let [key,server] of Object.entries(signalingServers)){ openForServer(key,server) } } class RTCClientContainer{ constructor(channel,connection,unorderChannel){ this.onclose = emptyFunc this.onmessage = emptyFunc this.channel = channel this.connection = connection this.unorderChannel = unorderChannel channel.addEventListener('message', msg => { const arr = new Uint8Array(msg.data) const packet = bitArrayToPacket(arr) this.onmessage(packet) }) unorderChannel.addEventListener('message', msg => { const arr = new Uint8Array(msg.data) const packet = bitArrayToPacket(arr) this.onmessage(packet) }) connection.addEventListener("connectionstatechange", e => { if(connection.connectionState === "closed" || connection.connectionState === "failed"){ this.onclose(), this.onclose = emptyFunc } }) channel.addEventListener("close", () => { this.connection.close() this.onclose(), this.onclose = emptyFunc }) } send(data){ let channel = unorderedPackets.has(data.type) ? this.unorderChannel : this.channel if(channel.readyState !== "open") return console.warn("Data channel not open, trying to send",data,"through",channel.label) data = packetToBitArray(data) try{ channel.send(data) }catch(e){ if(e&&e.name&&e.name==="OperationError") this.close() // close when full else throw e } } close(){ this.connection.close() this.onclose(), this.onclose = emptyFunc } } let saveInterval = setInterval(()=>{save()},300000) if(!serverWorld.playersInv.wn)serverWorld.playersInv.wn={} if(!serverWorld.playersInv.wn.fcreated)serverWorld.playersInv.wn.fcreated=Date.now()+"" if(!+serverWorld.playersInv.wn.ptime)serverWorld.playersInv.wn.ptime="0" let fcreated=serverWorld.playersInv.wn&&serverWorld.playersInv.wn.fcreated let lastptime=serverWorld.playersInv.wn&&serverWorld.playersInv.wn.ptime let word try{word=await import("/assets/word.js")}catch{} if(!serverWorld.playersInv.wn.wn)serverWorld.playersInv.wn.wn=(word&&word.default.noun[Math.floor(Math.random()*word.default.noun.length)]||ƒgenWord())+serverWorld.id[0]; if(serverWorld.playersInv.wn.wn.includes("->"))serverWorld.playersInv.wn.wn=serverWorld.playersInv.wn.wn.substring(0,serverWorld.playersInv.wn.wn.indexOf("->")) let prevusername=player.username,previd=player.id let lastun=localStorage.getItem("lastun"); let username if(lastun)username=lastun else if(word){word.default.init();username=word.default.generateName();localStorage.setItem("lastun",username)} else username=ƒgenWord() serverWorld.on("ping",e=>{e.data.fcreated=fcreated;e.data.name=window.serverWorld&&serverWorld.playersInv.wn&&serverWorld.playersInv.wn.wn;e.data.ptime=lastptime;e.data.host=username;if(!serverWorld.players.length)e.data.players.unshift(username)}) let getsavecs=new Set(), lastsave async function sendsave(c,d){ if(c.sending)return let idx=0;c.sending=true while(idx
{ if(e.data.id[0]==="."){ getsavecs.add(e.connection); e.connection.onclose=()=>{e.connection.sending=false;getsavecs.delete(e.connection);addm("-getsave "+e.data.username)}; if(lastsave)sendsave(e.connection,lastsave) addm("+getsave "+e.data.id+" , "+e.data.username) serverWorld.playersInv.wn.ptime=+serverWorld.playersInv.wn.ptime+1+"" return "stop" } }) function saveJSONReplacer(key,value){ if(value instanceof Uint8Array) return value.toString() else return value } serverWorld.on("save",e=>{ lastsave=JSON.stringify(e,saveJSONReplacer); if(exh){e.loadString=e.code;e.code=null} for(let c of getsavecs)sendsave(c,lastsave) serverWorld.playersInv.wn.ptime=+serverWorld.playersInv.wn.ptime+getsavecs.size+"" }) if(!Array.isArray(serverWorld.playersInv.wn.cm))serverWorld.playersInv.wn.cm=[] let cmlen=0;for(let m of serverWorld.playersInv.wn.cm)cmlen+=m.length function addcm(m){serverWorld.playersInv.wn.cm.push(m); cmlen+=m.length; while(cmlen>100000){cmlen-=serverWorld.playersInv.wn.cm[0].length;serverWorld.playersInv.wn.cm.shift()} } addcm("opened by "+username) serverWorld.oldsendAll=serverWorld.sendAll serverWorld.sendAll=function(m){if(m.type==="message"){addcm(m.data)};this.oldsendAll(m)} serverWorld.on("message",e=>{addcm(e.player.username+": "+e.data.data)}) if(serverWorld.players[0]){ serverWorld.players[0].connection.oldsend=serverWorld.players[0].connection.send serverWorld.players[0].connection.send=function(m){if(m.type!=="message"&&!(m.type==="pos"&&m.FROM))this.oldsend(m)} } save()//for lastsave enableMultiplayer() let worker try{ worker = new Worker(URL.createObjectURL(new Blob([`setInterval(() => self.postMessage(0), 1000 / 20);`], { type: 'application/javascript' }))); let lastRan = -Infinity; worker.onmessage = () => { let now=performance.now(); if (now - lastRan < 48) return; serverWorld.oldtick(); lastRan = now; }; serverWorld.oldtick=serverWorld.oldtick||serverWorld.tick serverWorld.tick=worker.onmessage }catch(e){addm("§c"+e)} try{ if(window.navigator&&navigator.userAgentData&&navigator.userAgentData.platform.includes("Chrome")){document.title="Google"} }catch(e){addm("§c"+e)} serverWorld.oldclose=serverWorld.oldclose||serverWorld.close serverWorld.close=()=>{ if(!sigConns)return disableMultiplayer() inWorld=0 window.serverWorld=null //so it won't reuse worker.terminate();clearInterval(saveInterval); window.scrt=2;serverWorld.event("close") } function closeit(){ if(!sigConns)return disableMultiplayer() inWorld=0 window.serverWorld=null //so it won't reuse worker.terminate();clearInterval(saveInterval); window.scrt=2;serverWorld.event("close") } window.closeit=closeit while(window.scrt){ let now=Date.now() lastptime=serverWorld.playersInv.wn.ptime let foundone, foundf,foundfcreated=fcreated, foundpf,foundptime=lastptime getWorlds(w=>{ w.ping=0; if(window.serverWorld&&w.id.includes(serverWorld.id)&&+w.fcreated>+foundfcreated&&+w.fcreated
+foundptime){ foundptime=+w.ptime foundpf=w closeit() } }) await sleep(60000) if(window.getWorldsWs) getWorldsWs.close() foundone=foundone||foundpf||foundf if(foundone){ addm("found "+foundone.name+", host:"+foundone.host) player.id="."+username let lastcon=Date.now(), con async function recon(){ addm("recon on "+foundone.signalingServer) let previd=player.id,prevun=player.username con=await initMultiplayer(foundone) if(window.bottomRightList)bottomRightList.innerHTML="" if(!con||con.cAnCeLcOnNectION)return con=null let str=[] con.onmessage=async e=>{ if(e.data)return str.push(e.data) else {str=str.join("");e.data=JSON.parse(str),str=[]} if(!e.data.playersInv.wn)e.data.playersInv.wn={}; e.data.playersInv.wn.fcreated=Date.now()+""; let ex=await loadFromDB(e.data.id) if(!ex||ex.loadString){e.data.loadString=e.data.code;e.data.code=null} saveToDB(e.data.id,e.data); window.lastw=e.data.id;localStorage.setItem("lastw",window.lastw) lastcon=Date.now() addm("saved") } con.onclose=e=>con=null } let stillany=3 while(Date.now()-lastcon<13*60000 && stillany>0){ if(!con)recon() let nowstillany getWorlds(w=>{if(w.id===foundone.id){foundone=w;nowstillany=true}}) await sleep(10000) if(window.getWorldsWs) getWorldsWs.close() if(nowstillany)stillany=3 else stillany-- if(nowstillany)await sleep(60000) } if(con)con.close() addm("nomore, savedrecently:"+(Date.now()-lastcon<13*60000)+" stillany:"+stillany+" lastw:"+lastw) player.id=previd window.scrt=0 } } } if(window.scrt&&window.serverWorld&&serverWorld.playersInv.wn)serverWorld.playersInv.wn.ptime=+serverWorld.playersInv.wn.ptime+serverWorld.players.length+"" // players*time if(window.scrt&&date.getDate()!==startday){startday=date.getDate();try{serverWorld.sendAll({type:"message",fromServer:true,data:"restarting"});await sleep(5000);await save();localStorage.setItem("lastw",serverWorld.id);location.reload()}catch{}} }, 1000); let startday=new Date().getDate() let f=[new Date().toLocaleString()],lastB=Date.now()+12.4254*60*1000 addEventListener("focus",e=>{f.push("+ "+new Date().toLocaleString());lastB=null;if(window.scrt){if(window.serverWorld)serverWorld.sendAll({type:"message",data:"panic!",fromServer:true});}});addEventListener("blur",e=>{f.push("- "+new Date().toLocaleString());lastB=Date.now()+43.67*60*1000}) window.lastw=localStorage.getItem("lastw"); window.sendError = e => { if(window.Messages){ try{ Messages.write("§c"+e.substring(0,190)) }catch{} } }