verb seek complete
This commit is contained in:
parent
12f1283e4e
commit
534ffeaf8e
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,6 +1,7 @@
|
|||||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||||
|
|
||||||
the_big_db.db
|
the_big_db.db
|
||||||
|
dump*.json
|
||||||
|
|
||||||
# dependencies
|
# dependencies
|
||||||
node_modules
|
node_modules
|
||||||
|
@ -19,7 +19,7 @@ function Live({editing, ...props}) {
|
|||||||
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, lastJsonMessage, readyState } = useWebSocket(`${wsUrl}/embody`, {
|
||||||
onClose: () => setConnecting(false)
|
onClose: () => setConnecting(false)
|
||||||
}, connecting);
|
}, connecting);
|
||||||
|
|
||||||
@ -35,23 +35,34 @@ function Live({editing, ...props}) {
|
|||||||
}
|
}
|
||||||
}, [lastMessage]);
|
}, [lastMessage]);
|
||||||
|
|
||||||
function handleSendMessage() {
|
// spread this return value on <a/> elements in order to make them navigate
|
||||||
console.log("sending a message...");
|
const commandLinkClick = (e) => {
|
||||||
sendMessage("button got clicked");
|
if (e.target.tagName != "A") { return; }
|
||||||
}
|
if (!e.target.href.includes(window.location.origin)) { return; }
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const localLink = e.target.href.replace(window.location.origin, "");
|
||||||
|
const targetString = localLink.replace("/", "");
|
||||||
|
const targetNumber = Number(targetString);
|
||||||
|
|
||||||
|
if (targetNumber != 0 && targetNumber != NaN) {
|
||||||
|
const warpMessage = `warp #${targetString}`;
|
||||||
|
console.log(`clicked a link, executing "warp #${targetString}"`);
|
||||||
|
sendMessage(warpMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
navigate(e.target.href.replace(window.location.origin, ""));
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Page editing={editing} number={currentNumber} {...props}/>
|
<Page editing={editing} number={currentNumber} linkClick={commandLinkClick} {...props} />
|
||||||
<MessageFeed messages={messageHistory}>
|
<MessageFeed messages={messageHistory}>
|
||||||
<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>
|
<button onClick={()=> setMessageHistory([])}>Clear History</button>
|
||||||
</MessageFeed>
|
</MessageFeed>
|
||||||
<Sidebar pagenumber={currentNumber} hidden="true" sendWord={(word) => setCommand((command + " " + word).trim())}>
|
<Sidebar pagenumber={currentNumber} hidden="true" sendWord={(word) => setCommand((command + " " + word).trim())}>
|
||||||
{!editing && <li><button onClick={() => navigate(`/${currentNumber}/edit`)}>edit</button></li>}
|
|
||||||
{editing && <li><button disabled={postMutation.isPending} onClick={submitChanges}>save</button></li>}
|
|
||||||
{editing && <li><button onClick={() => navigate(`/${currentNumber}`)}>return</button></li>}
|
|
||||||
</Sidebar>
|
</Sidebar>
|
||||||
<CommandEntry onSubmit={sendMessage}/>
|
<CommandEntry onSubmit={sendMessage}/>
|
||||||
</>
|
</>
|
||||||
|
@ -2,7 +2,6 @@ import { useState } from 'react';
|
|||||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||||
import { useParams, useNavigate } from 'react-router-dom';
|
import { useParams, useNavigate } from 'react-router-dom';
|
||||||
import { apiUrl, fetchPage, fetchPageAtEdit, postPage, deletePage } from '../apiTools.jsx';
|
import { apiUrl, fetchPage, fetchPageAtEdit, postPage, deletePage } from '../apiTools.jsx';
|
||||||
import { useFixLinks } from '../clientStuff.jsx';
|
|
||||||
import { useLoggedIn } from '../AuthProvider.jsx';
|
import { useLoggedIn } from '../AuthProvider.jsx';
|
||||||
import Page from './Page.jsx';
|
import Page from './Page.jsx';
|
||||||
|
|
||||||
@ -10,10 +9,21 @@ import './Pages.css';
|
|||||||
|
|
||||||
function GhostPage({editing, ...props}) {
|
function GhostPage({editing, ...props}) {
|
||||||
const { pagenumber, editid } = useParams();
|
const { pagenumber, editid } = useParams();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
return (
|
const linkClick = (e) => {
|
||||||
<Page number={pagenumber} editid={editid} editing={editing} {...props}/>
|
if (e.target.tagName != "A") { return; }
|
||||||
);
|
if (!e.target.href.includes(window.location.origin)) { return; }
|
||||||
|
e.preventDefault();
|
||||||
|
navigate(e.target.href.replace(window.location.origin, ""));
|
||||||
|
};
|
||||||
|
|
||||||
|
return <Page
|
||||||
|
number={pagenumber}
|
||||||
|
editid={editid}
|
||||||
|
editing={editing}
|
||||||
|
linkClick={linkClick}
|
||||||
|
{...props}/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default GhostPage;
|
export default GhostPage;
|
@ -6,11 +6,10 @@ import { useLoggedIn } from '../AuthProvider.jsx';
|
|||||||
|
|
||||||
import './Pages.css';
|
import './Pages.css';
|
||||||
|
|
||||||
function Page({ editing, number, editid=null}) {
|
function Page({ editing, number, editid=null, linkClick=()=>{} }) {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const loggedIn = useLoggedIn();
|
const loggedIn = useLoggedIn();
|
||||||
const noLoad = useFixLinks();
|
|
||||||
|
|
||||||
const fetchQuery = useQuery({ // fetch the currrent values
|
const fetchQuery = useQuery({ // fetch the currrent values
|
||||||
queryKey: ['page', number, editid],
|
queryKey: ['page', number, editid],
|
||||||
@ -61,7 +60,7 @@ function Page({ editing, number, editid=null}) {
|
|||||||
<div className="main-column">
|
<div className="main-column">
|
||||||
<header>
|
<header>
|
||||||
<h1>
|
<h1>
|
||||||
<a href="/" {...noLoad}>🌳</a>
|
<a href="/" onClick={linkClick}>🌳</a>
|
||||||
{number}.
|
{number}.
|
||||||
<span
|
<span
|
||||||
contentEditable={editing}
|
contentEditable={editing}
|
||||||
@ -80,7 +79,7 @@ function Page({ editing, number, editid=null}) {
|
|||||||
:
|
:
|
||||||
<div
|
<div
|
||||||
dangerouslySetInnerHTML={{__html: html}}
|
dangerouslySetInnerHTML={{__html: html}}
|
||||||
{...noLoad} />
|
onClick={linkClick} />
|
||||||
)
|
)
|
||||||
:
|
:
|
||||||
"..."
|
"..."
|
||||||
|
11
server/db_scripts/dump_24-10-10.js
Normal file
11
server/db_scripts/dump_24-10-10.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
const sqlite = require("better-sqlite3");
|
||||||
|
const db = new sqlite('the_big_db.db', { verbose: console.log });
|
||||||
|
|
||||||
|
const fs = require('node:fs');
|
||||||
|
|
||||||
|
const dump = {
|
||||||
|
pages: db.prepare('select * from pages').all(),
|
||||||
|
users: db.prepare('select * from users').all()
|
||||||
|
};
|
||||||
|
|
||||||
|
fs.writeFile(`dump_${new Date().toISOString()}.json`, JSON.stringify(dump), (err) => console.log(err) );
|
187
server/db_scripts/initialize_db-24-10-10.1.js
Normal file
187
server/db_scripts/initialize_db-24-10-10.1.js
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
// wipe and load the database from a dump file created by dump_blahblah.js
|
||||||
|
const hljs = require('highlight.js/lib/core');
|
||||||
|
hljs.registerLanguage('lua', require('highlight.js/lib/languages/lua'));
|
||||||
|
|
||||||
|
const fs = require('node:fs');
|
||||||
|
const sqlite = require("better-sqlite3");
|
||||||
|
const showdown = require("showdown");
|
||||||
|
const db = new sqlite('the_big_db.db', { verbose: console.log });
|
||||||
|
|
||||||
|
const converter = new showdown.Converter();
|
||||||
|
|
||||||
|
const dump_file_name = process.argv[2]
|
||||||
|
//get argument out of 'node db_scripts/initialize_db-blah-blah.js dumpfile'
|
||||||
|
|
||||||
|
let data = "{}";
|
||||||
|
try {
|
||||||
|
data = fs.readFileSync(dump_file_name, 'utf8');
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//open that file as text (unicode i guess?)
|
||||||
|
console.log("opened file");
|
||||||
|
const filejson = JSON.parse(data);
|
||||||
|
//parse it as json
|
||||||
|
|
||||||
|
|
||||||
|
const pages = filejson["pages"];
|
||||||
|
|
||||||
|
const createPages = db.prepare(`
|
||||||
|
create table if not exists pages (
|
||||||
|
id integer primary key,
|
||||||
|
number integer,
|
||||||
|
|
||||||
|
title varchar(255),
|
||||||
|
|
||||||
|
description text,
|
||||||
|
html text,
|
||||||
|
lua text,
|
||||||
|
|
||||||
|
time timestamp default current_timestamp,
|
||||||
|
author integer,
|
||||||
|
|
||||||
|
type integer
|
||||||
|
)
|
||||||
|
`);
|
||||||
|
/* an object has:
|
||||||
|
id = primary key
|
||||||
|
number = object identifier number
|
||||||
|
|
||||||
|
title / NAME = a short display name for an object, or the title of a page
|
||||||
|
description / TEXT? = the markdown description of an object, or the lua script of the source code of a verb
|
||||||
|
|
||||||
|
html / HTML_MARKDOWN? = the markdown for that object, rendered into html for display as a page
|
||||||
|
HTML_LUA? = the lua source code of the object, rendered into html with syntax highlighting?
|
||||||
|
|
||||||
|
time = when this edit was saved
|
||||||
|
author = the user id of whoever authored this revision
|
||||||
|
|
||||||
|
TYPE = whether this represents an object or a verb
|
||||||
|
*/
|
||||||
|
|
||||||
|
function migratePages(pages) {
|
||||||
|
console.log("moving old table to a temporary");
|
||||||
|
console.log(db.prepare(`alter table pages rename to old_pages`).run())
|
||||||
|
|
||||||
|
console.log("creating new page table")
|
||||||
|
console.log(createPages.run());
|
||||||
|
|
||||||
|
console.log('iterating over dump pages');
|
||||||
|
|
||||||
|
const insertPage = db.prepare(`insert into pages
|
||||||
|
(id, number, title, description, html, lua, time, author, type)
|
||||||
|
values (:id, :number, :title, :description, :html, :lua, :time, :author, :type)`);
|
||||||
|
|
||||||
|
pages.forEach((pageData) => {
|
||||||
|
let {id, number, description} = pageData;
|
||||||
|
console.log(`rendering page number ${number}.${id}`)
|
||||||
|
description = description.replace(/<br>/g, "\n");
|
||||||
|
|
||||||
|
const renderedPage = converter.makeHtml(description);
|
||||||
|
|
||||||
|
const highlightedLua = hljs.highlight(description, {language: 'lua'}).value;
|
||||||
|
|
||||||
|
args = { ...pageData, description: description, html: renderedPage, lua: highlightedLua, type: "noun"};
|
||||||
|
|
||||||
|
console.log("inserting args", args);
|
||||||
|
insertPage.run(args);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("getting rid of old table");
|
||||||
|
console.log(db.prepare("drop table old_pages").run());
|
||||||
|
|
||||||
|
//throw new Error("blahhh i'm a dracula");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
db.transaction(migratePages)(filejson["pages"]);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const createAttributesQuery = db.prepare(`
|
||||||
|
create table if not exists attributes (
|
||||||
|
number integer unique,
|
||||||
|
contents json
|
||||||
|
)
|
||||||
|
`);
|
||||||
|
/* an attribute store has:
|
||||||
|
number = the object number it's attached to
|
||||||
|
contents = a `text` object holding a json store of attributes defined on object #number, containing:
|
||||||
|
LOCATION? = the object which contains this object? should this be in the DB or in the json store?
|
||||||
|
PROTOTYPE = the number of the prototype for this object, to which we should look for attributes not found here
|
||||||
|
ATTRIBUTES? = json object of attached, script-controlled attributes.
|
||||||
|
|
||||||
|
CONTENTS = json array of objectss contained inside this one
|
||||||
|
VERBS = json array of objecsts which are verbs on this one
|
||||||
|
*/
|
||||||
|
function createAttributes() {
|
||||||
|
console.log("creating new attribute table")
|
||||||
|
console.log(createAttributesQuery.run());
|
||||||
|
|
||||||
|
console.log('iterating over all pages');
|
||||||
|
|
||||||
|
const insertAttribute = db.prepare(`insert into attributes
|
||||||
|
(number, contents) values (:number, :contents)`);
|
||||||
|
|
||||||
|
db.prepare(`select * from pages`).all().forEach((pageData) => {
|
||||||
|
let { number } = pageData;
|
||||||
|
|
||||||
|
let args = {contents: JSON.stringify({}), number: number};
|
||||||
|
|
||||||
|
console.log("inserting args", args);
|
||||||
|
insertAttribute.run(args);
|
||||||
|
});
|
||||||
|
|
||||||
|
//throw new Error("blahhh i'm a dracula");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
db.transaction(createAttributes)();
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const createUsers = db.prepare(`
|
||||||
|
create table if not exists users (
|
||||||
|
id integer primary key,
|
||||||
|
|
||||||
|
name varchar(64) unique,
|
||||||
|
password varchar(128),
|
||||||
|
|
||||||
|
character integer
|
||||||
|
)
|
||||||
|
`);
|
||||||
|
/* a user has:
|
||||||
|
id = primary key
|
||||||
|
name = name string
|
||||||
|
password = argon2 hash of their password
|
||||||
|
|
||||||
|
character = object in the game world representing your character
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function migrateUsers(users) {
|
||||||
|
console.log("moving old users");
|
||||||
|
console.log(db.prepare("alter table users rename to old_users").run());
|
||||||
|
|
||||||
|
console.log("creating new users table");
|
||||||
|
console.log(createUsers.run());
|
||||||
|
|
||||||
|
const insertUser = db.prepare("insert into users (name, password) values (:name, :password)")
|
||||||
|
users.forEach((user) => {
|
||||||
|
console.log(insertUser.run(user));
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("clearing old table");
|
||||||
|
console.log(db.prepare("drop table old_users").run());
|
||||||
|
//throw new Error("i'm dracula 2");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
db.transaction(migrateUsers)(filejson["users"]);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
@ -22,6 +22,34 @@ create table if not exists pages (
|
|||||||
author integer
|
author integer
|
||||||
)
|
)
|
||||||
`);
|
`);
|
||||||
|
/* an object has:
|
||||||
|
id = primary key
|
||||||
|
number = object identifier number
|
||||||
|
|
||||||
|
title / NAME = a short display name for an object, or the title of a page
|
||||||
|
description / TEXT? = the markdown description of an object, or the lua script of the source code of a verb
|
||||||
|
|
||||||
|
html / HTML_MARKDOWN? = the markdown for that object, rendered into html for display as a page
|
||||||
|
HTML_LUA? = the lua source code of the object, rendered into html with syntax highlighting?
|
||||||
|
|
||||||
|
time = when this edit was saved
|
||||||
|
author = the user id of whoever authored this revision
|
||||||
|
|
||||||
|
TYPE = whether this represents an object or a verb
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* an attribute store has:
|
||||||
|
number = the object number it's attached to
|
||||||
|
contents = a `text` object holding a json store of attributes defined on object #number, containing:
|
||||||
|
LOCATION? = the object which contains this object? should this be in the DB or in the json store?
|
||||||
|
PROTOTYPE = the number of the prototype for this object, to which we should look for attributes not found here
|
||||||
|
ATTRIBUTES? = json object of attached, script-controlled attributes.
|
||||||
|
|
||||||
|
CONTENTS = json array of objectss contained inside this one
|
||||||
|
VERBS = json array of objecsts which are verbs on this one
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
const createUsers = db.prepare(`
|
const createUsers = db.prepare(`
|
||||||
create table if not exists users (
|
create table if not exists users (
|
||||||
@ -31,7 +59,13 @@ create table if not exists users (
|
|||||||
password varchar(128)
|
password varchar(128)
|
||||||
)
|
)
|
||||||
`);
|
`);
|
||||||
|
/* a user has:
|
||||||
|
id = primary key
|
||||||
|
name = name string
|
||||||
|
password = argon2 hash of their password
|
||||||
|
|
||||||
|
character = object in the game world representing your character
|
||||||
|
*/
|
||||||
|
|
||||||
function migratePages() {
|
function migratePages() {
|
||||||
console.log("moving old table to a temporary");
|
console.log("moving old table to a temporary");
|
||||||
|
@ -10,19 +10,27 @@ function interpret(context, player, command) {
|
|||||||
// may be null if it's executing from a script?
|
// may be null if it's executing from a script?
|
||||||
// player: the id of the player object who typed in the command.
|
// 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.
|
// may? be null if it's executing from a script? used for output.
|
||||||
|
// so arguably
|
||||||
// command: the full string typed in by the player
|
// command: the full string typed in by the player
|
||||||
|
|
||||||
const socket = sockets.get(player)
|
const socket = sockets.get(player)
|
||||||
const words = command.trim().split(' ');
|
const words = command.trim().split(' ');
|
||||||
|
|
||||||
socket?.send(`interpreting and executing the received command: ${command}`);
|
try {
|
||||||
|
socket?.send(`interpreting and executing the received command: ${command}`);
|
||||||
|
|
||||||
const verbs = findAvailableVerbs(context, player, command);
|
//for the moment we'll only allow statements of the form "go north" with implicit subject: the player
|
||||||
socket?.send(`found these verbs: ${Array.from(verbs.keys()).join(', ')}`)
|
const [first, second, third, ...rest] = words;
|
||||||
|
|
||||||
// first word is either a subject or a verb. either way there must be a verb.
|
const verb = findVerb(first, context, player);
|
||||||
const [first, second, third, ...rest] = words;
|
|
||||||
|
|
||||||
|
console.log(`executing verb ${verb} towards ${player} on ${player} ${second} ${third}`);
|
||||||
|
executeVerb(player, verb, player, second, third, ...rest)
|
||||||
|
} catch (error) {
|
||||||
|
socket?.send(`got an error! ${error.mesage}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// if the second word is a verb, but the first word is also a verb, what do we do?
|
// 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) {
|
||||||
// for now, assume that if the second word is a verb, it's the verb we want.
|
// for now, assume that if the second word is a verb, it's the verb we want.
|
||||||
@ -31,16 +39,54 @@ function interpret(context, player, command) {
|
|||||||
// if the second word is not a verb, then the first word is the verb, and the player is the implied subject.
|
// 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)
|
executeVerb(player, verbs.get(first), player, second, third, ...rest)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
function findAvailableVerbs(location, actor, command) {
|
function findVerb(word, location, actor) {
|
||||||
|
// returns the number of a verb which matches the requested word.
|
||||||
// check for verbs on actor
|
// check for verbs on actor
|
||||||
// check for verbs on objects in location
|
let verb = findVerbOnObject(word, actor);
|
||||||
// check for verbs on location
|
if (verb) return verb;
|
||||||
const out = new Map();
|
|
||||||
out.set("look", 29);
|
const actorContents = getAttribute(actor, "contents");
|
||||||
out.set("warp", 31);
|
for (const obj of (actorContents || [])) {
|
||||||
return out;
|
verb = findVerbOnObject(word, obj);
|
||||||
|
if (verb) return verb;
|
||||||
|
}
|
||||||
|
|
||||||
|
const locationContents = getAttribute(location, "contents");
|
||||||
|
for (const obj of (locationContents || [])) {
|
||||||
|
verb = findVerbOnObject(word, obj);
|
||||||
|
if (verb) return verb;
|
||||||
|
}
|
||||||
|
|
||||||
|
verb = findVerbOnObject(word, location);
|
||||||
|
if (verb) return verb;
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function findVerbOnObject(word, object) {
|
||||||
|
// check for verbs on a single object, and its chain of parents. return a matching verbId, or undefined
|
||||||
|
if (!word) return undefined;
|
||||||
|
|
||||||
|
let focus = object;
|
||||||
|
while (focus) {
|
||||||
|
const focusVerbs = getAttribute(focus, "verbs");
|
||||||
|
for (const verbId of (focusVerbs || [])) {
|
||||||
|
const fullVerb = lookUpObject(verbId);
|
||||||
|
|
||||||
|
if (!fullVerb) continue;
|
||||||
|
|
||||||
|
// test our word against
|
||||||
|
if (word.toLowerCase() == fullVerb.title.toLowerCase()) {
|
||||||
|
return verbId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
focus = getAttribute(focus, "parent");
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function executeVerb(outputObject, verbId, subject, object, ...rest) {
|
function executeVerb(outputObject, verbId, subject, object, ...rest) {
|
||||||
@ -56,28 +102,99 @@ function executeVerb(outputObject, verbId, subject, object, ...rest) {
|
|||||||
return fullVerb.fn(outputObject, subject, object, ...rest);
|
return fullVerb.fn(outputObject, subject, object, ...rest);
|
||||||
}
|
}
|
||||||
|
|
||||||
const objectQuery = db.prepare('select * from pages where id=?');
|
const objectQuery = db.prepare('select * from pages where number=? order by time desc');
|
||||||
function lookUpObject(id) {
|
function lookUpObject(number) {
|
||||||
|
return hardCodedObjects(number) || objectQuery.get(number);
|
||||||
|
}
|
||||||
|
|
||||||
|
const attributeQuery = db.prepare(`select * from attributes where number=?`);
|
||||||
|
function lookUpObjectAttributes(number) {
|
||||||
|
return JSON.parse(attributeQuery.get(number).contents);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function hardCodedObjects(id) {
|
||||||
// return objectQuery.get(id);
|
// return objectQuery.get(id);
|
||||||
if (id == 30) return {name: "shoofle", contents: "this is a shoofle", location: 1};
|
|
||||||
if (id == 29) return {
|
if (id == 29) return {
|
||||||
name: "look",
|
title: "look",
|
||||||
verb: false,
|
verb: true,
|
||||||
contents: "send description of direct object to subject's socket",
|
description: "send description of direct object to subject's socket",
|
||||||
fn: (logReceiver, subject, object, ...rest) => {
|
fn: (logReceiver, subject, object, ...rest) => {
|
||||||
sockets.get(logReceiver)?.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}, and output was directed to ${logReceiver}`);
|
console.log(`${subject} looked at ${object} with args ${rest}, and output was directed to ${logReceiver}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (id == 31) return {
|
if (id == 31) return {
|
||||||
name: "warp",
|
title: "warp",
|
||||||
verb: true,
|
verb: true,
|
||||||
contents: "this built-in function changes the player's location, as well as telling their client to move",
|
description: "this built-in function changes the player's location, as well as telling their client to move",
|
||||||
fn: (logReceiver, subject, object, ...rest) => {
|
fn: (logReceiver, subject, object, ...rest) => {
|
||||||
// TODO: change subject's location
|
const objectNum = verifyObjectReference(object);
|
||||||
|
const subjectNum = verifyObjectReference(subject);
|
||||||
|
setAttribute(subjectNum, "location", objectNum);
|
||||||
|
|
||||||
sockets.get(logReceiver)?.send(`location change to: ${object}`);
|
sockets.get(logReceiver)?.send(`location change to: ${object}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { interpret, sockets, lookUpObject };
|
|
||||||
|
|
||||||
|
|
||||||
|
const pullAttribute = db.prepare(`select * from attributes where number=?`);
|
||||||
|
function getAttribute(obj, attributeName) {
|
||||||
|
const attributeStore = pullAttribute.get(verifyObjectReference(obj));
|
||||||
|
const contents = JSON.parse(attributeStore.contents);
|
||||||
|
|
||||||
|
if (contents.hasOwnProperty(attributeName)) {
|
||||||
|
return contents[attributeName];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contents.hasOwnProperty("parent")) {
|
||||||
|
return getAttribute(contents.parent, attributeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasOwnAttribute(obj, attributeName) {
|
||||||
|
const attributeStore = pullAttribute.get(verifyObjectReference(obj));
|
||||||
|
const contents = JSON.parse(attributeStore.contents);
|
||||||
|
|
||||||
|
return contents.hasOwnProperty(attributeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
const insertAttribute = db.prepare(`update or replace attributes set contents=:contents where number=:number`);
|
||||||
|
function setAttribute(obj, attributeName, value) {
|
||||||
|
const attributeStore = pullAttribute.get(verifyObjectReference(obj));
|
||||||
|
const contents = JSON.parse(attributeStore.contents);
|
||||||
|
|
||||||
|
contents[attributeName] = value;
|
||||||
|
|
||||||
|
insertAttribute.run({...attributeStore, contents: JSON.stringify(contents)});
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteAttribute(obj, attributeName) {
|
||||||
|
const attributeStore = pullAttribute.get(verifyObjectReference(obj));
|
||||||
|
const contents = JSON.parse(attributeStore.contents);
|
||||||
|
|
||||||
|
delete contents["attributeName"];
|
||||||
|
|
||||||
|
insertAttribute.run({...attributeStore, contents: JSON.stringify(contents)});
|
||||||
|
}
|
||||||
|
|
||||||
|
function verifyObjectReference(obj) {
|
||||||
|
try {
|
||||||
|
if (typeof(obj) === "string") {
|
||||||
|
return Number(obj.replace("#", ""));
|
||||||
|
} else if (typeof(obj) === "number") {
|
||||||
|
return obj;
|
||||||
|
} else if (typeof(obj.number) == "number") {
|
||||||
|
return obj.number;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error("Tried to get an attribute from something which wasn't an object");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { interpret, sockets, lookUpObject, getAttribute, setAttribute, deleteAttribute, hasOwnAttribute };
|
9
server/package-lock.json
generated
9
server/package-lock.json
generated
@ -21,6 +21,7 @@
|
|||||||
"graphology-layout": "^0.6.1",
|
"graphology-layout": "^0.6.1",
|
||||||
"graphology-layout-force": "^0.2.4",
|
"graphology-layout-force": "^0.2.4",
|
||||||
"graphology-layout-forceatlas2": "^0.10.1",
|
"graphology-layout-forceatlas2": "^0.10.1",
|
||||||
|
"highlight.js": "^11.10.0",
|
||||||
"jsdom": "^25.0.0",
|
"jsdom": "^25.0.0",
|
||||||
"nodemon": "^3.1.5",
|
"nodemon": "^3.1.5",
|
||||||
"showdown": "^2.1.0"
|
"showdown": "^2.1.0"
|
||||||
@ -1128,6 +1129,14 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/highlight.js": {
|
||||||
|
"version": "11.10.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.10.0.tgz",
|
||||||
|
"integrity": "sha512-SYVnVFswQER+zu1laSya563s+F8VDGt7o35d4utbamowvUNLLMovFqwCLSocpZTz3MgaSRA1IbqRWZv97dtErQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/html-encoding-sniffer": {
|
"node_modules/html-encoding-sniffer": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz",
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
"graphology-layout": "^0.6.1",
|
"graphology-layout": "^0.6.1",
|
||||||
"graphology-layout-force": "^0.2.4",
|
"graphology-layout-force": "^0.2.4",
|
||||||
"graphology-layout-forceatlas2": "^0.10.1",
|
"graphology-layout-forceatlas2": "^0.10.1",
|
||||||
|
"highlight.js": "^11.10.0",
|
||||||
"jsdom": "^25.0.0",
|
"jsdom": "^25.0.0",
|
||||||
"nodemon": "^3.1.5",
|
"nodemon": "^3.1.5",
|
||||||
"showdown": "^2.1.0"
|
"showdown": "^2.1.0"
|
||||||
|
@ -7,7 +7,8 @@ const db = new sqlite('the_big_db.db', { verbose: console.log });
|
|||||||
|
|
||||||
const { loginRequired } = require('../authStuff.js');
|
const { loginRequired } = require('../authStuff.js');
|
||||||
|
|
||||||
const { interpret, sockets, lookUpObject } = require('../interpreter.js');
|
const { interpret, sockets, lookUpObject,
|
||||||
|
getAttribute, setAttribute, hasOwnAttribute, deleteAttribute } = require('../interpreter.js');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -15,6 +16,7 @@ app.ws('/embody', (ws, req) => {
|
|||||||
// const { playerObject } = db.prepare('select playerObject from users where id=?').get(req.session.userId)
|
// const { playerObject } = db.prepare('select playerObject from users where id=?').get(req.session.userId)
|
||||||
const playerObjectId = 30; // mocked out for now!
|
const playerObjectId = 30; // mocked out for now!
|
||||||
sockets.set(playerObjectId, ws);
|
sockets.set(playerObjectId, ws);
|
||||||
|
ws.send(`location change to: #${getAttribute(playerObjectId, "location")}`);
|
||||||
|
|
||||||
ws.on('message', (msg) => {
|
ws.on('message', (msg) => {
|
||||||
const location = lookUpObject(playerObjectId).location;
|
const location = lookUpObject(playerObjectId).location;
|
||||||
|
Loading…
Reference in New Issue
Block a user