mocking out some interpreter functions
This commit is contained in:
parent
940fc15b90
commit
12f1283e4e
@ -3,19 +3,27 @@
|
|||||||
margin-bottom: 2rem;
|
margin-bottom: 2rem;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
background: lightblue;
|
padding: 0;
|
||||||
|
background: lightgreen;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 20%;
|
left: 20%;
|
||||||
right: 20%;
|
right: 20%;
|
||||||
|
border-radius: 1rem;
|
||||||
|
}
|
||||||
|
.commandline form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
.commandline input {
|
.commandline input {
|
||||||
|
flex: 10;
|
||||||
font-size: 16pt;
|
font-size: 16pt;
|
||||||
border: none;
|
border: none;
|
||||||
padding: 1rem;
|
padding: 2rem;
|
||||||
width: calc(100% - 2rem);
|
|
||||||
margin-left: 0;
|
|
||||||
margin-right: 0;
|
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.commandline button {
|
||||||
|
}
|
@ -1,10 +1,16 @@
|
|||||||
|
import { useForm } from "react-hook-form";
|
||||||
|
|
||||||
import './CommandEntry.css';
|
import './CommandEntry.css';
|
||||||
|
|
||||||
function CommandEntry({command, onChange, onSubmit, ...props}) {
|
function CommandEntry({ onSubmit }) {
|
||||||
|
const { register, handleSubmit, setValue } = useForm();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="commandline">
|
<div className="commandline">
|
||||||
<input type="text" placeholder="Enter a command!" value={command} onChange={onChange} {...props}/>
|
<form onSubmit={handleSubmit((data) => { setValue('command', ""); onSubmit(data.command); })}>
|
||||||
<button onClick={() => onSubmit(command)}>Do</button>
|
<input {...register("command")} autoFocus type="text" placeholder="Enter a command!" />
|
||||||
|
<button type="submit">Do</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -14,24 +14,27 @@ import CommandEntry from './CommandEntry.jsx';
|
|||||||
function Live({editing, ...props}) {
|
function Live({editing, ...props}) {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const loggedIn = useLoggedIn();
|
const loggedIn = useLoggedIn();
|
||||||
const { pagenumber } = useParams();
|
|
||||||
const [command, setCommand] = useState("");
|
|
||||||
const [ messageHistory, setMessageHistory ] = useState([]);
|
const [ messageHistory, setMessageHistory ] = useState([]);
|
||||||
const [ currentNumber, setCurrentNumber ] = useState(1);
|
const [ currentNumber, setCurrentNumber ] = useState(1);
|
||||||
|
|
||||||
const [ connecting, setConnecting ] = useState(true);
|
const [ connecting, setConnecting ] = useState(true);
|
||||||
|
|
||||||
const { sendMessage, lastMessage, readyState } = useWebSocket(`${wsUrl}/embody`, {
|
const { sendMessage, lastMessage, readyState } = useWebSocket(`${wsUrl}/embody`, {
|
||||||
onClose: () => setConnecting(false)
|
onClose: () => setConnecting(false)
|
||||||
}, connecting);
|
}, connecting);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (lastMessage !== null) {
|
if (lastMessage !== null) {
|
||||||
|
console.log(lastMessage);
|
||||||
setMessageHistory((prev) => prev.concat(lastMessage));
|
setMessageHistory((prev) => prev.concat(lastMessage));
|
||||||
|
|
||||||
|
if (lastMessage.data.startsWith("location change to: ")) {
|
||||||
|
const num = Number(lastMessage.data.replace("location change to: #", ""));
|
||||||
|
setCurrentNumber(num);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [lastMessage]);
|
}, [lastMessage]);
|
||||||
|
|
||||||
useEffect(() => { sendMessage("what the fuk is up"); }, []);
|
|
||||||
|
|
||||||
function handleSendMessage() {
|
function handleSendMessage() {
|
||||||
console.log("sending a message...");
|
console.log("sending a message...");
|
||||||
sendMessage("button got clicked");
|
sendMessage("button got clicked");
|
||||||
@ -43,16 +46,14 @@ function Live({editing, ...props}) {
|
|||||||
<MessageFeed messages={messageHistory}>
|
<MessageFeed messages={messageHistory}>
|
||||||
<button disabled={readyState!=ReadyState.OPEN} onClick={handleSendMessage}>send a message to the server!</button>
|
<button disabled={readyState!=ReadyState.OPEN} onClick={handleSendMessage}>send a message to the server!</button>
|
||||||
<button disabled={connecting} onClick={() => setConnecting(true)}>Reconnect</button>
|
<button disabled={connecting} onClick={() => setConnecting(true)}>Reconnect</button>
|
||||||
|
<button onClick={()=> setMessageHistory([])}>Clear History</button>
|
||||||
</MessageFeed>
|
</MessageFeed>
|
||||||
<Sidebar pagenumber={pagenumber} hidden="true" sendWord={(word) => setCommand((command + " " + word).trim())}>
|
<Sidebar pagenumber={currentNumber} hidden="true" sendWord={(word) => setCommand((command + " " + word).trim())}>
|
||||||
{!editing && <li><button onClick={() => navigate(`/${pagenumber}/edit`)}>edit</button></li>}
|
{!editing && <li><button onClick={() => navigate(`/${currentNumber}/edit`)}>edit</button></li>}
|
||||||
{editing && <li><button disabled={postMutation.isPending} onClick={submitChanges}>save</button></li>}
|
{editing && <li><button disabled={postMutation.isPending} onClick={submitChanges}>save</button></li>}
|
||||||
{editing && <li><button onClick={() => navigate(`/${pagenumber}`)}>return</button></li>}
|
{editing && <li><button onClick={() => navigate(`/${currentNumber}`)}>return</button></li>}
|
||||||
</Sidebar>
|
</Sidebar>
|
||||||
<CommandEntry
|
<CommandEntry onSubmit={sendMessage}/>
|
||||||
command={command}
|
|
||||||
onChange={(e) => setCommand(e.target.value)}
|
|
||||||
onSubmit={(e) => { setCommand(""); sendMessage(e); }}/>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,25 @@
|
|||||||
.messages-tray {
|
.messages-tray {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
transition: all 0.1s linear;
|
transition: all 0.1s linear;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
background: lightblue;
|
background: lightgreen;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
width: 30ch;
|
width: 30ch;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
left: 0;
|
left: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.messages-hidden {
|
.messages-hidden {
|
||||||
transform: translateX(-20ch);
|
transform: translateX(-20ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar li {
|
.messages-tray ol {
|
||||||
|
flex: 10;
|
||||||
|
padding-left: 1ch;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
.messages-tray li {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar li button {
|
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-hidden li {
|
|
||||||
display: none;
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useState, useCallback } from 'react';
|
import { useEffect, useState, useRef } from 'react';
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
@ -6,16 +6,18 @@ import './MessageFeed.css';
|
|||||||
|
|
||||||
function MessageFeed({messages=[], children}) {
|
function MessageFeed({messages=[], children}) {
|
||||||
const [ open, setOpen ] = useState(false);
|
const [ open, setOpen ] = useState(false);
|
||||||
|
const listContainer = useRef(null);
|
||||||
|
|
||||||
|
useEffect(() => listContainer.current.scrollTo(0, listContainer.current.scrollHeight), [listContainer, messages])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`messages-tray ${!open?'messages-hidden':''}`}>
|
<div className={`messages-tray ${!open?'messages-hidden':''}`}>
|
||||||
<button style={{float: 'right'}} onClick={() => setOpen(!open)}>{open?'Hide':'Show'}</button>
|
<button style={{float: 'right'}} onClick={() => setOpen(!open)}>{open?'Hide':'Show'}</button>
|
||||||
<h2>Message history:</h2>
|
<h2>Message history:</h2>
|
||||||
<ol>
|
<ol ref={listContainer}>
|
||||||
{messages.map((message, idx) =>
|
{messages.map((message, idx) =>
|
||||||
<li key={idx}>
|
<li key={idx}>
|
||||||
{message.data}
|
{message.data}
|
||||||
<code style={{background: "lightgrey"}}>{JSON.stringify(message)}</code>
|
|
||||||
</li>
|
</li>
|
||||||
)}
|
)}
|
||||||
</ol>
|
</ol>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
.sidebar {
|
.sidebar {
|
||||||
transition: all 0.1s linear;
|
transition: all 0.1s linear;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
background: lightblue;
|
background: lightgreen;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
width: 30ch;
|
width: 30ch;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -9,10 +9,10 @@ import Page from './Page.jsx';
|
|||||||
import './Pages.css';
|
import './Pages.css';
|
||||||
|
|
||||||
function GhostPage({editing, ...props}) {
|
function GhostPage({editing, ...props}) {
|
||||||
const { pagenumber } = useParams();
|
const { pagenumber, editid } = useParams();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page number={pagenumber} editing={editing} {...props}/>
|
<Page number={pagenumber} editid={editid} editing={editing} {...props}/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,17 +6,15 @@ import { useLoggedIn } from '../AuthProvider.jsx';
|
|||||||
|
|
||||||
import './Pages.css';
|
import './Pages.css';
|
||||||
|
|
||||||
function Page({ editing, number }) {
|
function Page({ editing, number, editid=null}) {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { editid } = useParams();
|
|
||||||
const pagenumber = number
|
|
||||||
const loggedIn = useLoggedIn();
|
const loggedIn = useLoggedIn();
|
||||||
const noLoad = useFixLinks();
|
const noLoad = useFixLinks();
|
||||||
|
|
||||||
const fetchQuery = useQuery({ // fetch the currrent values
|
const fetchQuery = useQuery({ // fetch the currrent values
|
||||||
queryKey: ['page', pagenumber, editid],
|
queryKey: ['page', number, editid],
|
||||||
queryFn: () => editid ? fetchPageAtEdit(pagenumber, editid) : fetchPage(pagenumber)
|
queryFn: () => editid ? fetchPageAtEdit(number, editid) : fetchPage(number)
|
||||||
})
|
})
|
||||||
|
|
||||||
const postMutation = useMutation({ // for changing the value when we're done with it
|
const postMutation = useMutation({ // for changing the value when we're done with it
|
||||||
@ -46,16 +44,16 @@ function Page({ editing, number }) {
|
|||||||
const newTitle = document.querySelector('span').innerHTML;
|
const newTitle = document.querySelector('span').innerHTML;
|
||||||
const newText = document.querySelector('pre').innerHTML;
|
const newText = document.querySelector('pre').innerHTML;
|
||||||
postMutation.mutate({
|
postMutation.mutate({
|
||||||
id: pagenumber,
|
id: number,
|
||||||
title: newTitle,
|
title: newTitle,
|
||||||
description: newText
|
description: newText
|
||||||
});
|
});
|
||||||
navigate(`/${pagenumber}`, {replace: true})
|
navigate(`/${number}`, {replace: true})
|
||||||
}
|
}
|
||||||
|
|
||||||
function submitDelete(e) {
|
function submitDelete(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
deleteMutation.mutate(pagenumber);
|
deleteMutation.mutate(number);
|
||||||
navigate(`/`);
|
navigate(`/`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,7 +62,7 @@ function Page({ editing, number }) {
|
|||||||
<header>
|
<header>
|
||||||
<h1>
|
<h1>
|
||||||
<a href="/" {...noLoad}>🌳</a>
|
<a href="/" {...noLoad}>🌳</a>
|
||||||
{pagenumber}.
|
{number}.
|
||||||
<span
|
<span
|
||||||
contentEditable={editing}
|
contentEditable={editing}
|
||||||
dangerouslySetInnerHTML={{__html: readyToShow ? title : "..." }} />
|
dangerouslySetInnerHTML={{__html: readyToShow ? title : "..." }} />
|
||||||
@ -89,7 +87,7 @@ function Page({ editing, number }) {
|
|||||||
}
|
}
|
||||||
</section>
|
</section>
|
||||||
<button
|
<button
|
||||||
onClick={() => navigate(`/${pagenumber}/history`)}>
|
onClick={() => navigate(`/${number}/history`)}>
|
||||||
History
|
History
|
||||||
</button>
|
</button>
|
||||||
{editing && (
|
{editing && (
|
||||||
@ -101,7 +99,7 @@ function Page({ editing, number }) {
|
|||||||
{!editing && !editid && (
|
{!editing && !editid && (
|
||||||
<button
|
<button
|
||||||
disabled={!loggedIn}
|
disabled={!loggedIn}
|
||||||
onClick={() => navigate(`/${pagenumber}/edit`)}>
|
onClick={() => navigate(`/${number}/edit`)}>
|
||||||
Edit Page
|
Edit Page
|
||||||
</button>)}
|
</button>)}
|
||||||
{loggedIn && (
|
{loggedIn && (
|
||||||
|
@ -3,31 +3,57 @@ const db = new sqlite('the_big_db.db', { verbose: console.log });
|
|||||||
|
|
||||||
var sockets = new Map();
|
var sockets = new Map();
|
||||||
|
|
||||||
function interpret(context, subject, command) {
|
function interpret(context, player, command) {
|
||||||
const words = command.split(' ');
|
// interpret and execute a command entered by a player.
|
||||||
|
//
|
||||||
|
// context: the location the player has entered the command in from.
|
||||||
|
// may be null if it's executing from a script?
|
||||||
|
// player: the id of the player object who typed in the command.
|
||||||
|
// may? be null if it's executing from a script? used for output.
|
||||||
|
// command: the full string typed in by the player
|
||||||
|
|
||||||
|
const socket = sockets.get(player)
|
||||||
|
const words = command.trim().split(' ');
|
||||||
|
|
||||||
|
socket?.send(`interpreting and executing the received command: ${command}`);
|
||||||
|
|
||||||
|
const verbs = findAvailableVerbs(context, player, command);
|
||||||
|
socket?.send(`found these verbs: ${Array.from(verbs.keys()).join(', ')}`)
|
||||||
|
|
||||||
const verbs = findVerbs(context, subject);
|
|
||||||
// first word is either a subject or a verb. either way there must be a verb.
|
// first word is either a subject or a verb. either way there must be a verb.
|
||||||
// check if the first word is in the list of verbs.
|
|
||||||
const [first, second, third, ...rest] = words;
|
const [first, second, third, ...rest] = words;
|
||||||
|
|
||||||
|
// if the second word is a verb, but the first word is also a verb, what do we do?
|
||||||
if (second in verbs) {
|
if (second in verbs) {
|
||||||
executeVerb(verbs.get(second), first, third, ...rest);
|
// for now, assume that if the second word is a verb, it's the verb we want.
|
||||||
|
executeVerb(player, verbs.get(second), first, third, ...rest);
|
||||||
} else {
|
} else {
|
||||||
executeVerb(verbs.get(first), subject, second, third, ...rest)
|
// if the second word is not a verb, then the first word is the verb, and the player is the implied subject.
|
||||||
|
executeVerb(player, verbs.get(first), player, second, third, ...rest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function findVerbs(location, actor) {
|
function findAvailableVerbs(location, actor, command) {
|
||||||
// check for verbs on actor
|
// check for verbs on actor
|
||||||
// check for verbs on objects in location
|
// check for verbs on objects in location
|
||||||
// check for verbs on location
|
// check for verbs on location
|
||||||
const out = new Map();
|
const out = new Map();
|
||||||
out.set("look", 29);
|
out.set("look", 29);
|
||||||
|
out.set("warp", 31);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
function executeVerb(verb, subject, object, ...rest) {
|
function executeVerb(outputObject, verbId, subject, object, ...rest) {
|
||||||
lookUpObject(verb).fn(subject, object, ...rest)
|
const fullVerb = lookUpObject(verbId);
|
||||||
|
if (!fullVerb) {
|
||||||
|
return sockets.get(outputObject)?.send(`verb not found`);
|
||||||
|
}
|
||||||
|
sockets.get(outputObject)?.send(`verb found as ${fullVerb.name}`);
|
||||||
|
const func = fullVerb.fn;
|
||||||
|
if (!func) {
|
||||||
|
return sockets.get(outputObject)?.send(`verb was found but didn't have a fn attribute`);
|
||||||
|
}
|
||||||
|
return fullVerb.fn(outputObject, subject, object, ...rest);
|
||||||
}
|
}
|
||||||
|
|
||||||
const objectQuery = db.prepare('select * from pages where id=?');
|
const objectQuery = db.prepare('select * from pages where id=?');
|
||||||
@ -36,12 +62,22 @@ function lookUpObject(id) {
|
|||||||
if (id == 30) return {name: "shoofle", contents: "this is a shoofle", location: 1};
|
if (id == 30) return {name: "shoofle", contents: "this is a shoofle", location: 1};
|
||||||
if (id == 29) return {
|
if (id == 29) return {
|
||||||
name: "look",
|
name: "look",
|
||||||
|
verb: false,
|
||||||
contents: "send description of direct object to subject's socket",
|
contents: "send description of direct object to subject's socket",
|
||||||
fn: (subject, object, ...rest) => {
|
fn: (logReceiver, subject, object, ...rest) => {
|
||||||
sockets.get(subject)?.send(`you looked around! subject: ${subject} object: ${object} args: ${rest}`);
|
sockets.get(logReceiver)?.send(`you looked around! subject ${subject} object: ${object} args: ${rest}`);
|
||||||
console.log(`${subject} looked at ${object} with args ${rest}`);
|
console.log(`${subject} looked at ${object} with args ${rest}, and output was directed to ${logReceiver}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (id == 31) return {
|
||||||
|
name: "warp",
|
||||||
|
verb: true,
|
||||||
|
contents: "this built-in function changes the player's location, as well as telling their client to move",
|
||||||
|
fn: (logReceiver, subject, object, ...rest) => {
|
||||||
|
// TODO: change subject's location
|
||||||
|
sockets.get(logReceiver)?.send(`location change to: ${object}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { interpret, sockets, lookUpObject };
|
module.exports = { interpret, sockets, lookUpObject };
|
@ -9,17 +9,6 @@ const { loginRequired } = require('../authStuff.js');
|
|||||||
|
|
||||||
const { interpret, sockets, lookUpObject } = require('../interpreter.js');
|
const { interpret, sockets, lookUpObject } = require('../interpreter.js');
|
||||||
|
|
||||||
const clockListeners = new Set();
|
|
||||||
const clock = setInterval(() => {
|
|
||||||
if (clockListeners.size == 0) return;
|
|
||||||
console.log(`sending a ping to all ${clockListeners.size} connections`);
|
|
||||||
clockListeners.forEach((x) => x());
|
|
||||||
}, 5000);
|
|
||||||
console.log(`set up the clock: ${clock}`);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
app.ws('/embody', (ws, req) => {
|
app.ws('/embody', (ws, req) => {
|
||||||
@ -38,5 +27,4 @@ app.ws('/embody', (ws, req) => {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = app;
|
module.exports = app;
|
Loading…
Reference in New Issue
Block a user