Stuff and junk
This commit is contained in:
269
server/public/index.html
Executable file
269
server/public/index.html
Executable file
@@ -0,0 +1,269 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>WebSocket MUD</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: 'Courier New', monospace;
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
color: #00ff00;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
#container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100vh;
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#output {
|
||||||
|
flex: 1;
|
||||||
|
background-color: #000;
|
||||||
|
border: 2px solid #333;
|
||||||
|
padding: 15px;
|
||||||
|
overflow-y: auto;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.4;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#input-container {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#input {
|
||||||
|
flex: 1;
|
||||||
|
background-color: #222;
|
||||||
|
border: 2px solid #333;
|
||||||
|
color: #00ff00;
|
||||||
|
padding: 10px;
|
||||||
|
font-family: 'Courier New', monospace;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#input:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: #00ff00;
|
||||||
|
}
|
||||||
|
|
||||||
|
#send {
|
||||||
|
background-color: #333;
|
||||||
|
border: 2px solid #555;
|
||||||
|
color: #00ff00;
|
||||||
|
padding: 10px 20px;
|
||||||
|
font-family: 'Courier New', monospace;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#send:hover {
|
||||||
|
background-color: #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
#status {
|
||||||
|
background-color: #333;
|
||||||
|
padding: 5px 15px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.connected {
|
||||||
|
color: #00ff00;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disconnected {
|
||||||
|
color: #ff4444;
|
||||||
|
}
|
||||||
|
|
||||||
|
.connecting {
|
||||||
|
color: #ffaa00;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
color: #ff4444;
|
||||||
|
}
|
||||||
|
|
||||||
|
.system {
|
||||||
|
color: #aaaaaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt {
|
||||||
|
color: #00ccff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="container">
|
||||||
|
<div id="status" class="connecting">Connecting...</div>
|
||||||
|
<div id="output"></div>
|
||||||
|
<div id="input-container">
|
||||||
|
<input type="text" id="input" placeholder="Enter command..." disabled>
|
||||||
|
<button id="send" disabled>Send</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
class MUDClient {
|
||||||
|
constructor() {
|
||||||
|
this.ws = null;
|
||||||
|
this.output = document.getElementById('output');
|
||||||
|
this.input = document.getElementById('input');
|
||||||
|
this.sendButton = document.getElementById('send');
|
||||||
|
this.status = document.getElementById('status');
|
||||||
|
|
||||||
|
this.setupEventListeners();
|
||||||
|
this.connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||||
|
const wsUrl = `${protocol}//${window.location.host}`;
|
||||||
|
|
||||||
|
this.updateStatus('Connecting...', 'connecting');
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.ws = new WebSocket(wsUrl);
|
||||||
|
|
||||||
|
this.ws.onopen = () => {
|
||||||
|
this.updateStatus('Connected', 'connected');
|
||||||
|
this.input.disabled = false;
|
||||||
|
this.sendButton.disabled = false;
|
||||||
|
this.input.focus();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.ws.onmessage = (event) => {
|
||||||
|
const data = JSON.parse(event.data);
|
||||||
|
this.handleMessage(data);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.ws.onclose = () => {
|
||||||
|
this.updateStatus('Disconnected', 'disconnected');
|
||||||
|
this.input.disabled = true;
|
||||||
|
this.sendButton.disabled = true;
|
||||||
|
|
||||||
|
// Attempt to reconnect after 3 seconds
|
||||||
|
setTimeout(() => this.connect(), 3000);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.ws.onerror = (error) => {
|
||||||
|
this.updateStatus('Connection Error', 'error');
|
||||||
|
this.appendOutput('Connection error occurred. Retrying...', 'error');
|
||||||
|
};
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
this.updateStatus('Connection Failed', 'error');
|
||||||
|
setTimeout(() => this.connect(), 3000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setupEventListeners() {
|
||||||
|
this.input.addEventListener('keypress', (e) => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
this.sendMessage();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.sendButton.addEventListener('click', () => {
|
||||||
|
this.sendMessage();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Command history
|
||||||
|
this.commandHistory = [];
|
||||||
|
this.historyIndex = -1;
|
||||||
|
|
||||||
|
this.input.addEventListener('keydown', (e) => {
|
||||||
|
if (e.key === 'ArrowUp') {
|
||||||
|
e.preventDefault();
|
||||||
|
if (this.historyIndex < this.commandHistory.length - 1) {
|
||||||
|
this.historyIndex++;
|
||||||
|
this.input.value = this.commandHistory[this.commandHistory.length - 1 - this.historyIndex];
|
||||||
|
}
|
||||||
|
} else if (e.key === 'ArrowDown') {
|
||||||
|
e.preventDefault();
|
||||||
|
if (this.historyIndex > 0) {
|
||||||
|
this.historyIndex--;
|
||||||
|
this.input.value = this.commandHistory[this.commandHistory.length - 1 - this.historyIndex];
|
||||||
|
} else if (this.historyIndex === 0) {
|
||||||
|
this.historyIndex = -1;
|
||||||
|
this.input.value = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
sendMessage() {
|
||||||
|
const message = this.input.value.trim();
|
||||||
|
if (message && this.ws && this.ws.readyState === WebSocket.OPEN) {
|
||||||
|
// Add to command history
|
||||||
|
if (this.commandHistory[this.commandHistory.length - 1] !== message) {
|
||||||
|
this.commandHistory.push(message);
|
||||||
|
if (this.commandHistory.length > 50) {
|
||||||
|
this.commandHistory.shift();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.historyIndex = -1;
|
||||||
|
|
||||||
|
this.ws.send(JSON.stringify({
|
||||||
|
type: 'command',
|
||||||
|
content: message
|
||||||
|
}));
|
||||||
|
|
||||||
|
this.input.value = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleMessage(data) {
|
||||||
|
switch (data.type) {
|
||||||
|
case 'message':
|
||||||
|
this.appendOutput(data.content);
|
||||||
|
break;
|
||||||
|
case 'error':
|
||||||
|
this.appendOutput(data.content, 'error');
|
||||||
|
break;
|
||||||
|
case 'system':
|
||||||
|
this.appendOutput(data.content, 'system');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
this.appendOutput(data.content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
appendOutput(text, className = '') {
|
||||||
|
const div = document.createElement('div');
|
||||||
|
if (className) {
|
||||||
|
div.className = className;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if this looks like a prompt
|
||||||
|
if (text.includes('] > ')) {
|
||||||
|
div.className = 'prompt';
|
||||||
|
}
|
||||||
|
|
||||||
|
div.textContent = text;
|
||||||
|
this.output.appendChild(div);
|
||||||
|
this.output.scrollTop = this.output.scrollHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateStatus(message, className) {
|
||||||
|
this.status.textContent = `Status: ${message}`;
|
||||||
|
this.status.className = className;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize the MUD client when the page loads
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
new MUDClient();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -3,7 +3,17 @@ const http = require('http');
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Player
|
||||||
|
*
|
||||||
|
* @property WebSocket websocket
|
||||||
|
*/
|
||||||
class Player {
|
class Player {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {String} name
|
||||||
|
* @param {WebSocket} websocket
|
||||||
|
*/
|
||||||
constructor(name, websocket) {
|
constructor(name, websocket) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.websocket = websocket;
|
this.websocket = websocket;
|
||||||
@@ -13,6 +23,11 @@ class Player {
|
|||||||
this.level = 1;
|
this.level = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* Send a message back to the client via the websocket.
|
||||||
|
*
|
||||||
|
* @param {string} message
|
||||||
|
*/
|
||||||
sendMessage(message) {
|
sendMessage(message) {
|
||||||
if (this.websocket.readyState === WebSocket.OPEN) {
|
if (this.websocket.readyState === WebSocket.OPEN) {
|
||||||
this.websocket.send(JSON.stringify({
|
this.websocket.send(JSON.stringify({
|
||||||
@@ -28,6 +43,13 @@ class Player {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Room {
|
class Room {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} id
|
||||||
|
* @param {string} name
|
||||||
|
* @param {string} description
|
||||||
|
* @param {string[]} exits
|
||||||
|
*/
|
||||||
constructor(id, name, description, exits = {}) {
|
constructor(id, name, description, exits = {}) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
@@ -38,22 +60,45 @@ class Room {
|
|||||||
this.npcs = [];
|
this.npcs = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a player to the list of active players.
|
||||||
|
*
|
||||||
|
* (an active player is a player that currently has an active web socketA)
|
||||||
|
*
|
||||||
|
* @param {Player} player
|
||||||
|
*/
|
||||||
addPlayer(player) {
|
addPlayer(player) {
|
||||||
this.players.add(player);
|
this.players.add(player);
|
||||||
this.broadcastToRoom(`${player.name} enters the room.`, player);
|
this.broadcastToRoom(`${player.name} enters the room.`, player);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a player from the list of active players.
|
||||||
|
*
|
||||||
|
* (an active player is a player that currently has an active web socketA)
|
||||||
|
*
|
||||||
|
* @param {Player} player
|
||||||
|
*/
|
||||||
removePlayer(player) {
|
removePlayer(player) {
|
||||||
this.players.delete(player);
|
this.players.delete(player);
|
||||||
this.broadcastToRoom(`${player.name} leaves the room.`, player);
|
this.broadcastToRoom(`${player.name} leaves the room.`, player);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a message to all other players in this room.
|
||||||
|
*
|
||||||
|
* @param {string} message
|
||||||
|
* @param {Player} excludePlayer A single player to exclude from the broadcast
|
||||||
|
*/
|
||||||
broadcastToRoom(message, excludePlayer = null) {
|
broadcastToRoom(message, excludePlayer = null) {
|
||||||
for (const player of this.players) {
|
// for (const player of this.players) {
|
||||||
if (player !== excludePlayer) {
|
// if (player !== excludePlayer) {
|
||||||
|
// player.sendMessage(message);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
this.getPlayersExcept(excludePlayer).forEach((player) => {
|
||||||
player.sendMessage(message);
|
player.sendMessage(message);
|
||||||
}
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getPlayersExcept(excludePlayer) {
|
getPlayersExcept(excludePlayer) {
|
||||||
@@ -104,6 +149,10 @@ class MudServer {
|
|||||||
this.rooms.set('deep_forest', deepForest);
|
this.rooms.set('deep_forest', deepForest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {WebSocket} ws
|
||||||
|
*/
|
||||||
handleConnection(ws) {
|
handleConnection(ws) {
|
||||||
console.log('New connection established');
|
console.log('New connection established');
|
||||||
|
|
||||||
@@ -126,6 +175,12 @@ class MudServer {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {WebSocket} ws
|
||||||
|
* @param {strings} message
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
handleMessage(ws, message) {
|
handleMessage(ws, message) {
|
||||||
const player = this.players.get(ws);
|
const player = this.players.get(ws);
|
||||||
|
|
||||||
@@ -147,6 +202,11 @@ class MudServer {
|
|||||||
this.processCommand(player, message.content.trim());
|
this.processCommand(player, message.content.trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {WebSocket} ws
|
||||||
|
* @param {string} name
|
||||||
|
*/
|
||||||
createPlayer(ws, name) {
|
createPlayer(ws, name) {
|
||||||
const player = new Player(name, ws);
|
const player = new Player(name, ws);
|
||||||
this.players.set(ws, player);
|
this.players.set(ws, player);
|
||||||
@@ -159,6 +219,11 @@ class MudServer {
|
|||||||
this.showRoom(player);
|
this.showRoom(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Player} player
|
||||||
|
* @param {string} input
|
||||||
|
*/
|
||||||
processCommand(player, input) {
|
processCommand(player, input) {
|
||||||
const args = input.toLowerCase().split(' ');
|
const args = input.toLowerCase().split(' ');
|
||||||
const command = args[0];
|
const command = args[0];
|
||||||
@@ -232,6 +297,12 @@ class MudServer {
|
|||||||
player.sendPrompt();
|
player.sendPrompt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Player} player
|
||||||
|
* @param {*} direction
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
movePlayer(player, direction) {
|
movePlayer(player, direction) {
|
||||||
const currentRoom = this.rooms.get(player.currentRoom);
|
const currentRoom = this.rooms.get(player.currentRoom);
|
||||||
const newRoomId = currentRoom.exits[direction];
|
const newRoomId = currentRoom.exits[direction];
|
||||||
|
|||||||
Reference in New Issue
Block a user