mirror of
https://github.com/PrismarineJS/prismarine-web-client.git
synced 2024-11-24 08:37:51 -05:00
add code
This commit is contained in:
parent
d186c09a0b
commit
d978f5c762
11 changed files with 434 additions and 56 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
|||
node_modules/
|
||||
package-lock.json
|
||||
.vscode
|
||||
public
|
38
README.md
38
README.md
|
@ -1,23 +1,33 @@
|
|||
# prismarine-template
|
||||
[![NPM version](https://img.shields.io/npm/v/prismarine-template.svg)](http://npmjs.com/package/prismarine-template)
|
||||
[![Build Status](https://github.com/PrismarineJS/prismarine-template/workflows/CI/badge.svg)](https://github.com/PrismarineJS/prismarine-template/actions?query=workflow%3A%22CI%22)
|
||||
# prismarine-web-client
|
||||
[![NPM version](https://img.shields.io/npm/v/prismarine-web-client.svg)](http://npmjs.com/package/prismarine-web-client)
|
||||
[![Build Status](https://github.com/PrismarineJS/prismarine-web-client/workflows/CI/badge.svg)](https://github.com/PrismarineJS/prismarine-web-client/actions?query=workflow%3A%22CI%22)
|
||||
[![Discord](https://img.shields.io/badge/chat-on%20discord-brightgreen.svg)](https://discord.gg/GsEFRM8)
|
||||
[![Gitter](https://img.shields.io/badge/chat-on%20gitter-brightgreen.svg)](https://gitter.im/PrismarineJS/general)
|
||||
[![Irc](https://img.shields.io/badge/chat-on%20irc-brightgreen.svg)](https://irc.gitter.im/)
|
||||
[![Try it on gitpod](https://img.shields.io/badge/try-on%20gitpod-brightgreen.svg)](https://gitpod.io/#https://github.com/PrismarineJS/prismarine-template)
|
||||
[![Try it on gitpod](https://img.shields.io/badge/try-on%20gitpod-brightgreen.svg)](https://gitpod.io/#https://github.com/PrismarineJS/prismarine-web-client)
|
||||
|
||||
A template repository to make it easy to create new prismarine repo
|
||||
A minecraft client running in a web page.
|
||||
|
||||
## Usage
|
||||
It runs mineflayer in the browser which connects to a websocket minecraft server.
|
||||
It provides a simple websocket to tcp proxy as a backend to make it possible to connect to any minecraft server.
|
||||
|
||||
## Features
|
||||
|
||||
* display blocks
|
||||
* display entities as colored rectangles
|
||||
* movement sync
|
||||
|
||||
## Roadmap
|
||||
|
||||
* chat
|
||||
* block placing and breaking
|
||||
|
||||
## Run
|
||||
|
||||
```js
|
||||
const template = require('prismarine-template')
|
||||
|
||||
template.helloWorld()
|
||||
npm install
|
||||
npm run build-start
|
||||
```
|
||||
|
||||
## API
|
||||
Then connect to http://localhost:8080
|
||||
|
||||
|
||||
### helloWorld()
|
||||
|
||||
Prints hello world
|
||||
|
|
39
dns.js
Normal file
39
dns.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
/* global XMLHttpRequest */
|
||||
|
||||
// Custom DNS resolver made by SiebeDW. Powered by google dns.
|
||||
// Supported: SRV (not all errors support)
|
||||
module.exports.resolveSrv = function (hostname, callback) {
|
||||
const Http = new XMLHttpRequest()
|
||||
const url = `https://dns.google.com/resolve?name=${hostname}&type=SRV`
|
||||
Http.open('GET', url)
|
||||
Http.responseType = 'json'
|
||||
Http.send()
|
||||
|
||||
Http.onload = function () {
|
||||
const response = Http.response
|
||||
if (response.Status === 3) {
|
||||
const err = new Error('querySrv ENOTFOUND')
|
||||
err.code = 'ENOTFOUND'
|
||||
callback(err)
|
||||
return
|
||||
}
|
||||
if (!response.Answer || response.Answer.length < 1) {
|
||||
const err = new Error('querySrv ENODATA')
|
||||
err.code = 'ENODATA'
|
||||
callback(err)
|
||||
return
|
||||
}
|
||||
const willreturn = []
|
||||
response.Answer.forEach(function (object) {
|
||||
const data = object.data.split(' ')
|
||||
willreturn.push({
|
||||
priority: data[0],
|
||||
weight: data[1],
|
||||
port: data[2],
|
||||
name: data[3]
|
||||
})
|
||||
})
|
||||
console.log(willreturn)
|
||||
callback(null, willreturn)
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
const template = require('prismarine-template')
|
||||
|
||||
template.helloWorld()
|
30
index.html
Normal file
30
index.html
Normal file
|
@ -0,0 +1,30 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Prismarine Viewer</title>
|
||||
<style type="text/css">
|
||||
html {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
canvas {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
font-size: 0;
|
||||
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript" src="index.js"></script>
|
||||
</body>
|
||||
</html>
|
135
index.js
135
index.js
|
@ -1,9 +1,132 @@
|
|||
if (typeof process !== 'undefined' && parseInt(process.versions.node.split('.')[0]) < 14) {
|
||||
console.error('Your node version is currently', process.versions.node)
|
||||
console.error('Please update it to a version >= 14.x.x from https://nodejs.org/')
|
||||
process.exit(1)
|
||||
/* global THREE, prompt */
|
||||
|
||||
// Workaround for process.versions.node not existing in the browser
|
||||
process.versions.node = '14.0.0'
|
||||
|
||||
const mineflayer = require('mineflayer')
|
||||
const { WorldView, Viewer } = require('prismarine-viewer/viewer')
|
||||
global.THREE = require('three')
|
||||
|
||||
async function main () {
|
||||
const viewDistance = 6
|
||||
const host = prompt('Host', '95.111.249.143')
|
||||
const port = parseInt(prompt('Port', '10000'))
|
||||
const username = prompt('Username', 'pviewer_person')
|
||||
let password = prompt('Password (blank for offline)')
|
||||
password = password === '' ? undefined : password
|
||||
console.log(`connecting to ${host} ${port} with ${username}`)
|
||||
|
||||
const bot = mineflayer.createBot({
|
||||
host,
|
||||
port,
|
||||
username,
|
||||
password
|
||||
})
|
||||
|
||||
bot.on('end', () => {
|
||||
console.log('disconnected')
|
||||
})
|
||||
|
||||
bot.once('spawn', () => {
|
||||
console.log('bot spawned - starting viewer')
|
||||
|
||||
const version = bot.version
|
||||
|
||||
const center = bot.entity.position
|
||||
|
||||
const worldView = new WorldView(bot.world, viewDistance, center)
|
||||
|
||||
// Create three.js context, add to page
|
||||
const renderer = new THREE.WebGLRenderer()
|
||||
renderer.setPixelRatio(window.devicePixelRatio || 1)
|
||||
renderer.setSize(window.innerWidth, window.innerHeight)
|
||||
document.body.appendChild(renderer.domElement)
|
||||
|
||||
// Create viewer
|
||||
const viewer = new Viewer(renderer)
|
||||
viewer.setVersion(version)
|
||||
|
||||
worldView.listenToBot(bot)
|
||||
worldView.init(bot.entity.position)
|
||||
|
||||
function botPosition () {
|
||||
viewer.setFirstPersonCamera(bot.entity.position, bot.entity.yaw, bot.entity.pitch)
|
||||
worldView.updatePosition(bot.entity.position)
|
||||
}
|
||||
|
||||
module.exports.helloWorld = function () {
|
||||
console.log('Hello world !')
|
||||
bot.on('move', botPosition)
|
||||
|
||||
// Link WorldView and Viewer
|
||||
viewer.listen(worldView)
|
||||
viewer.camera.position.set(center.x, center.y, center.z)
|
||||
|
||||
function moveCallback (e) {
|
||||
bot.entity.pitch -= e.movementY * 0.01
|
||||
bot.entity.yaw -= e.movementX * 0.01
|
||||
viewer.setFirstPersonCamera(bot.entity.position, bot.entity.yaw, bot.entity.pitch)
|
||||
}
|
||||
function changeCallback () {
|
||||
if (document.pointerLockElement === renderer.domElement ||
|
||||
document.mozPointerLockElement === renderer.domElement ||
|
||||
document.webkitPointerLockElement === renderer.domElement) {
|
||||
document.addEventListener('mousemove', moveCallback, false)
|
||||
} else {
|
||||
document.removeEventListener('mousemove', moveCallback, false)
|
||||
}
|
||||
}
|
||||
document.addEventListener('pointerlockchange', changeCallback, false)
|
||||
document.addEventListener('mozpointerlockchange', changeCallback, false)
|
||||
document.addEventListener('webkitpointerlockchange', changeCallback, false)
|
||||
renderer.domElement.requestPointerLock = renderer.domElement.requestPointerLock ||
|
||||
renderer.domElement.mozRequestPointerLock ||
|
||||
renderer.domElement.webkitRequestPointerLock
|
||||
document.addEventListener('mousedown', (e) => {
|
||||
renderer.domElement.requestPointerLock()
|
||||
})
|
||||
|
||||
document.addEventListener('contextmenu', (e) => e.preventDefault(), false)
|
||||
document.addEventListener('keydown', (e) => {
|
||||
console.log(e.code)
|
||||
if (e.code === 'KeyW') {
|
||||
bot.setControlState('forward', true)
|
||||
} else if (e.code === 'KeyS') {
|
||||
bot.setControlState('back', true)
|
||||
} else if (e.code === 'KeyA') {
|
||||
bot.setControlState('right', true)
|
||||
} else if (e.code === 'KeyD') {
|
||||
bot.setControlState('left', true)
|
||||
} else if (e.code === 'Space') {
|
||||
bot.setControlState('jump', true)
|
||||
} else if (e.code === 'ShiftLeft') {
|
||||
bot.setControlState('sneak', true)
|
||||
} else if (e.code === 'ControlLeft') {
|
||||
bot.setControlState('sprint', true)
|
||||
}
|
||||
}, false)
|
||||
document.addEventListener('keyup', (e) => {
|
||||
if (e.code === 'KeyW') {
|
||||
bot.setControlState('forward', false)
|
||||
} else if (e.code === 'KeyS') {
|
||||
bot.setControlState('back', false)
|
||||
} else if (e.code === 'KeyA') {
|
||||
bot.setControlState('right', false)
|
||||
} else if (e.code === 'KeyD') {
|
||||
bot.setControlState('left', false)
|
||||
} else if (e.code === 'Space') {
|
||||
bot.setControlState('jump', false)
|
||||
} else if (e.code === 'ShiftLeft') {
|
||||
bot.setControlState('sneak', false)
|
||||
} else if (e.code === 'ControlLeft') {
|
||||
bot.setControlState('sprint', false)
|
||||
}
|
||||
}, false)
|
||||
|
||||
// Browser animation loop
|
||||
const animate = () => {
|
||||
window.requestAnimationFrame(animate)
|
||||
renderer.render(viewer.scene, viewer.camera)
|
||||
}
|
||||
animate()
|
||||
})
|
||||
}
|
||||
main()
|
||||
|
|
61
package.json
61
package.json
|
@ -1,31 +1,50 @@
|
|||
{
|
||||
"name": "prismarine-template",
|
||||
"name": "web_client",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"description": "A template repository to make it easy to create new prismarine repo",
|
||||
"description": "web_client",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "jest --verbose",
|
||||
"pretest": "npm run lint",
|
||||
"prepare": "webpack",
|
||||
"start": "webpack serve",
|
||||
"prod-start": "node server.js",
|
||||
"build-start": "npm run prepare && npm run prod-start",
|
||||
"lint": "standard",
|
||||
"fix": "standard --fix"
|
||||
"fix": "standard --fix",
|
||||
"test": "npm run lint && mocha"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/PrismarineJS/prismarine-template.git"
|
||||
"dependencies": {
|
||||
"assert": "^2.0.0",
|
||||
"browserify-zlib": "^0.2.0",
|
||||
"buffer": "^6.0.3",
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
"compression": "^1.7.4",
|
||||
"constants-browserify": "^1.0.0",
|
||||
"copy-webpack-plugin": "^7.0.0",
|
||||
"crypto-browserify": "^3.12.0",
|
||||
"events": "^3.2.0",
|
||||
"express": "^4.17.1",
|
||||
"http-browserify": "^1.7.0",
|
||||
"https-browserify": "^1.0.0",
|
||||
"memfs": "^3.2.0",
|
||||
"mineflayer": "^2.39.2",
|
||||
"net-browserify": "^0.2.4",
|
||||
"os-browserify": "^0.3.0",
|
||||
"path-browserify": "^1.0.1",
|
||||
"prismarine-viewer": "^1.14.0",
|
||||
"process": "^0.11.10",
|
||||
"request": "^2.88.2",
|
||||
"stream-browserify": "^3.0.0",
|
||||
"three": "^0.124.0",
|
||||
"timers-browserify": "^2.0.12",
|
||||
"webpack": "^5.11.0",
|
||||
"webpack-cli": "^4.2.0",
|
||||
"webpack-dev-server": "^3.11.0"
|
||||
},
|
||||
"keywords": [
|
||||
"prismarine",
|
||||
"template"
|
||||
],
|
||||
"author": "Romain Beaumont",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/PrismarineJS/prismarine-template/issues"
|
||||
},
|
||||
"homepage": "https://github.com/PrismarineJS/prismarine-template#readme",
|
||||
"devDependencies": {
|
||||
"jest": "^26.1.0",
|
||||
"prismarine-template": "file:.",
|
||||
"standard": "^16.0.1"
|
||||
"http-server": "^0.12.3",
|
||||
"lodash-webpack-plugin": "^0.11.6",
|
||||
"mocha": "^8.3.0",
|
||||
"standard": "^16.0.3"
|
||||
}
|
||||
}
|
||||
|
|
1
perf_hooks_replacement.js
Normal file
1
perf_hooks_replacement.js
Normal file
|
@ -0,0 +1 @@
|
|||
module.exports.performance = window.performance
|
76
server.js
Normal file
76
server.js
Normal file
|
@ -0,0 +1,76 @@
|
|||
const express = require('express')
|
||||
const netApi = require('net-browserify')
|
||||
const bodyParser = require('body-parser')
|
||||
const request = require('request')
|
||||
const compression = require('compression')
|
||||
|
||||
// Create our app
|
||||
const app = express()
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
res.header('Access-Control-Allow-Origin', req.get('Origin') || '*')
|
||||
res.header('Access-Control-Allow-Credentials', 'true')
|
||||
res.header('Access-Control-Allow-Methods', 'GET,HEAD,PUT,PATCH,POST,DELETE')
|
||||
res.header('Access-Control-Expose-Headers', 'Content-Length')
|
||||
res.header(
|
||||
'Access-Control-Allow-Headers',
|
||||
'Accept, Authorization, Content-Type, X-Requested-With, Range'
|
||||
)
|
||||
if (req.method === 'OPTIONS') {
|
||||
return res.send(200)
|
||||
} else {
|
||||
return next()
|
||||
}
|
||||
})
|
||||
|
||||
app.use(compression())
|
||||
app.use(netApi())
|
||||
app.use(express.static('./public'))
|
||||
|
||||
app.use(bodyParser.json({ limit: '100kb' }))
|
||||
|
||||
app.all('*', function (req, res, next) {
|
||||
// Set CORS headers: allow all origins, methods, and headers: you may want to lock this down in a production environment
|
||||
res.header('Access-Control-Allow-Origin', '*')
|
||||
res.header('Access-Control-Allow-Methods', 'GET, PUT, PATCH, POST, DELETE')
|
||||
res.header(
|
||||
'Access-Control-Allow-Headers',
|
||||
req.header('access-control-request-headers')
|
||||
)
|
||||
|
||||
if (req.method === 'OPTIONS') {
|
||||
// CORS Preflight
|
||||
res.send()
|
||||
} else {
|
||||
const targetURL = req.header('Target-URL')
|
||||
if (!targetURL) {
|
||||
res.status(404).send({ error: '404 Not Found' })
|
||||
return
|
||||
}
|
||||
const newHeaders = req.headers
|
||||
newHeaders.host = targetURL
|
||||
.replace('https://', '')
|
||||
.replace('http://', '')
|
||||
.split('/')[0]
|
||||
request(
|
||||
{
|
||||
url: targetURL + req.url,
|
||||
method: req.method,
|
||||
json: req.body,
|
||||
headers: req.headers
|
||||
},
|
||||
function (error, response, body) {
|
||||
if (error) {
|
||||
console.error(error)
|
||||
console.error('error: ' + response.statusCode)
|
||||
}
|
||||
// console.log(body);
|
||||
}
|
||||
).pipe(res)
|
||||
}
|
||||
})
|
||||
|
||||
// Start the server
|
||||
const server = app.listen(8080, function () {
|
||||
console.log('Server listening on port ' + server.address().port)
|
||||
})
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-env jest */
|
||||
/* eslint-env mocha */
|
||||
|
||||
describe('basic', () => {
|
||||
test('test', () => {
|
||||
it('test', () => {
|
||||
|
||||
})
|
||||
})
|
||||
|
|
82
webpack.config.js
Normal file
82
webpack.config.js
Normal file
|
@ -0,0 +1,82 @@
|
|||
const webpack = require('webpack')
|
||||
const path = require('path')
|
||||
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin')
|
||||
const CopyPlugin = require('copy-webpack-plugin')
|
||||
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
|
||||
|
||||
const config = {
|
||||
// devtool: 'inline-source-map',
|
||||
// mode: 'development',
|
||||
mode: 'production',
|
||||
entry: path.resolve(__dirname, './index.js'),
|
||||
output: {
|
||||
path: path.resolve(__dirname, './public'),
|
||||
filename: './index.js'
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'minecraft-protocol': path.resolve(
|
||||
__dirname,
|
||||
'node_modules/minecraft-protocol/src/index.js'
|
||||
), // Hack to allow creating the client in a browser
|
||||
express: false,
|
||||
net: 'net-browserify',
|
||||
fs: 'memfs'
|
||||
},
|
||||
fallback: {
|
||||
zlib: require.resolve('browserify-zlib'),
|
||||
stream: require.resolve('stream-browserify'),
|
||||
buffer: require.resolve('buffer/'),
|
||||
events: require.resolve('events/'),
|
||||
assert: require.resolve('assert/'),
|
||||
crypto: require.resolve('crypto-browserify'),
|
||||
path: require.resolve('path-browserify'),
|
||||
constants: require.resolve('constants-browserify'),
|
||||
os: require.resolve('os-browserify/browser'),
|
||||
http: require.resolve('http-browserify'),
|
||||
https: require.resolve('https-browserify'),
|
||||
timers: require.resolve('timers-browserify'),
|
||||
// fs: require.resolve("fs-memory/singleton"),
|
||||
child_process: false,
|
||||
perf_hooks: path.resolve(__dirname, 'perf_hooks_replacement.js'),
|
||||
dns: path.resolve(__dirname, 'dns.js')
|
||||
}
|
||||
},
|
||||
plugins: [
|
||||
// fix "process is not defined" error:
|
||||
new CleanWebpackPlugin(),
|
||||
new webpack.ProvidePlugin({
|
||||
process: 'process/browser'
|
||||
}),
|
||||
new webpack.ProvidePlugin({
|
||||
Buffer: ['buffer', 'Buffer']
|
||||
}),
|
||||
new webpack.NormalModuleReplacementPlugin(
|
||||
/prismarine-viewer[/|\\]viewer[/|\\]lib[/|\\]utils/,
|
||||
'./utils.web.js'
|
||||
),
|
||||
new CopyPlugin({
|
||||
patterns: [
|
||||
{ from: 'index.html', to: './index.html' },
|
||||
{ from: 'node_modules/prismarine-viewer/public/blocksStates/', to: './blocksStates/' },
|
||||
{ from: 'node_modules/prismarine-viewer/public/textures/', to: './textures/' },
|
||||
{ from: 'node_modules/prismarine-viewer/public/worker.js', to: './' },
|
||||
{ from: 'node_modules/prismarine-viewer/public/supportedVersions.json', to: './' }
|
||||
]
|
||||
}),
|
||||
new webpack.optimize.ModuleConcatenationPlugin(),
|
||||
new LodashModuleReplacementPlugin()
|
||||
],
|
||||
devServer: {
|
||||
contentBase: path.resolve(__dirname, './public'),
|
||||
compress: true,
|
||||
inline: true,
|
||||
// open: true,
|
||||
hot: true,
|
||||
watchOptions: {
|
||||
ignored: /node_modules/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = config
|
Loading…
Reference in a new issue