Skip to content

Commit

Permalink
Implement enough of the Emglken FS to pass Glulxercise!
Browse files Browse the repository at this point in the history
  • Loading branch information
curiousdannii committed Mar 5, 2024
1 parent eae4af5 commit 5ff02f7
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 33 deletions.
4 changes: 3 additions & 1 deletion remglk/src/glkapi/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,14 +237,16 @@ pub const fileusage_SavedGame: u32 = 0x01;
pub const fileusage_Transcript: u32 = 0x02;
pub const fileusage_InputRecord: u32 = 0x03;
pub const fileusage_TypeMask: u32 = 0x0f;
#[derive(Clone, Copy, Default, Deserialize, PartialEq, Serialize)]
#[derive(Clone, Copy, Default, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[repr(C)]
#[serde(rename_all = "lowercase")]
pub enum FileType {
#[default]
Data = 0,
#[serde(rename="save")]
SavedGame,
Transcript,
#[serde(rename="command")]
InputRecord,
}
pub fn file_type(filetype: u32) -> FileType {
Expand Down
2 changes: 1 addition & 1 deletion remglk/src/glkapi/protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ pub enum FileRefResponse {
Fref(SystemFileRef),
}

#[derive(Clone, Default, Deserialize)]
#[derive(Clone, Default, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct SystemFileRef {
pub content: Option<String>,
pub filename: String,
Expand Down
54 changes: 35 additions & 19 deletions remglk_capi/src/systems/emglken.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,17 @@ use std::collections::HashMap;
use std::mem::MaybeUninit;
use std::slice;

use serde::de::DeserializeOwned;

use super::*;
use remglk::GlkSystem;
use glkapi::protocol::{Event, SystemFileRef, Update};

extern "C" {
fn emglken_fileref_exists(filename_ptr: *const u8, filename_len: usize) -> bool;
fn emglken_fileref_read(filename_ptr: *const u8, filename_len: usize, buffer: *mut EmglkenBuffer) -> bool;
fn emglken_fileref_delete(fref_ptr: *const u8, fref_len: usize);
fn emglken_fileref_exists(fref_ptr: *const u8, fref_len: usize) -> bool;
fn emglken_fileref_read(fref_ptr: *const u8, fref_len: usize, buffer: *mut EmglkenBuffer) -> bool;
fn emglken_fileref_temporary(filetype: FileType, buffer: *mut EmglkenBuffer);
fn emglken_get_glkote_event(buffer: *mut EmglkenBuffer);
fn emglken_send_glkote_update(update_ptr: *const u8, update_len: usize);
}
Expand All @@ -41,7 +45,7 @@ pub fn glkapi() -> &'static Mutex<GlkApi> {

#[derive(Default)]
pub struct EmglkenSystem {
cache: HashMap<String, Box<[u8]>>,
cache: HashMap<SystemFileRef, Box<[u8]>>,
}

impl GlkSystem for EmglkenSystem {
Expand All @@ -54,35 +58,43 @@ impl GlkSystem for EmglkenSystem {
}
}

fn fileref_delete(&mut self, _fileref: &SystemFileRef) {
unimplemented!()
fn fileref_delete(&mut self, fileref: &SystemFileRef) {
self.cache.remove(&fileref);
let json = serde_json::to_string(&fileref).unwrap();
unsafe {emglken_fileref_delete(json.as_ptr(), json.len())};
}

fn fileref_exists(&mut self, fileref: &SystemFileRef) -> bool {
self.cache.contains_key(&fileref.filename) || unsafe {emglken_fileref_exists(fileref.filename.as_ptr(), fileref.filename.len())}
self.cache.contains_key(&fileref) || {
let json = serde_json::to_string(&fileref).unwrap();
unsafe {emglken_fileref_exists(json.as_ptr(), json.len())}
}
}

fn fileref_read(&mut self, fileref: &SystemFileRef) -> Option<Box<[u8]>> {
// Check the cache first
if let Some(buf) = self.cache.get(&fileref.filename) {
if let Some(buf) = self.cache.get(&fileref) {
Some(buf.clone())
}
else {
let mut buf: MaybeUninit<EmglkenBuffer> = MaybeUninit::uninit();
let result = unsafe {emglken_fileref_read(fileref.filename.as_ptr(), fileref.filename.len(), buf.as_mut_ptr())};
let json = serde_json::to_string(&fileref).unwrap();
let result = unsafe {emglken_fileref_read(json.as_ptr(), json.len(), buf.as_mut_ptr())};
if result {
return Some(buffer_to_boxed_slice(&unsafe {buf.assume_init()}));
return Some(buffer_to_boxed_slice(buf));
}
None
}
}

fn fileref_temporary(&mut self, _filetype: FileType) -> SystemFileRef {
unimplemented!()
fn fileref_temporary(&mut self, filetype: FileType) -> SystemFileRef {
let mut buf: MaybeUninit<EmglkenBuffer> = MaybeUninit::uninit();
unsafe {emglken_fileref_temporary(filetype, buf.as_mut_ptr())};
buffer_to_protocol_struct(buf)
}

fn fileref_write_buffer(&mut self, _fileref: &SystemFileRef, _buf: Box<[u8]>) {
unimplemented!()
fn fileref_write_buffer(&mut self, fileref: &SystemFileRef, buf: Box<[u8]>) {
self.cache.insert(fileref.clone(), buf);
}

fn flush_writeable_files(&mut self) {
Expand All @@ -95,18 +107,22 @@ impl GlkSystem for EmglkenSystem {
fn get_glkote_event(&mut self) -> Option<Event> {
let mut buf: MaybeUninit<EmglkenBuffer> = MaybeUninit::uninit();
unsafe {emglken_get_glkote_event(buf.as_mut_ptr())};
let data = buffer_to_boxed_slice(&unsafe {buf.assume_init()});
let event: Event = serde_json::from_slice(&data).unwrap();
return Some(event);
Some(buffer_to_protocol_struct(buf))
}

fn send_glkote_update(&mut self, update: Update) {
// Send the update
let output = serde_json::to_string(&update).unwrap();
unsafe {emglken_send_glkote_update(output.as_ptr(), output.len())};
let json = serde_json::to_string(&update).unwrap();
unsafe {emglken_send_glkote_update(json.as_ptr(), json.len())};
}
}

fn buffer_to_boxed_slice(buffer: &EmglkenBuffer) -> Box<[u8]> {
fn buffer_to_boxed_slice(buffer: MaybeUninit<EmglkenBuffer>) -> Box<[u8]> {
let buffer = unsafe {buffer.assume_init()};
unsafe {Box::from_raw(slice::from_raw_parts_mut(buffer.ptr, buffer.len))}
}

fn buffer_to_protocol_struct<T: DeserializeOwned>(buffer: MaybeUninit<EmglkenBuffer>) -> T {
let data = buffer_to_boxed_slice(buffer);
serde_json::from_slice(&data).unwrap()
}
44 changes: 32 additions & 12 deletions remglk_capi/src/systems/library_emglken.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,44 +10,64 @@ https://github.com/curiousdannii/emglken
*/

addToLibrary({
emglken_fileref_exists(filename_ptr, filename_len) {
const name = UTF8ToString(filename_ptr, filename_len)
if (name === storyfile_name) {
emglken_fileref_delete(fref_ptr, fref_len) {
const fref = JSON.parse(UTF8ToString(fref_ptr, fref_len))
Dialog.file_remove_ref(fref)
},

emglken_fileref_exists(fref_ptr, fref_len) {
const fref = JSON.parse(UTF8ToString(fref_ptr, fref_len))
if (fref.filename === storyfile_name) {
return true
}
return false
else {
return Dialog.file_ref_exists(fref)
}
},

emglken_fileref_read__deps: ['$writeBuffer'],
emglken_fileref_read(filename_ptr, filename_len, buffer) {
const name = UTF8ToString(filename_ptr, filename_len)
if (name === storyfile_name) {
emglken_fileref_read(fref_ptr, fref_len, buffer) {
const fref = JSON.parse(UTF8ToString(fref_ptr, fref_len))
if (fref.filename === storyfile_name) {
writeBuffer(buffer, storyfile_data)
return true
}
return false
},

emglken_fileref_temporary__deps: ['$FILETYPES', '$writeBufferJSON'],
emglken_fileref_temporary(filetype, buffer) {
let fref = Dialog.file_construct_temp_ref(FILETYPES[filetype])
writeBufferJSON(buffer, fref)
},

emglken_get_glkote_event__async: true,
emglken_get_glkote_event__deps: ['$writeBuffer'],
emglken_get_glkote_event__deps: ['$writeBufferJSON'],
emglken_get_glkote_event(buffer) {
return Asyncify.handleAsync(async () => {
await new Promise(resolve => { glkote_event_ready = resolve })
writeBuffer(buffer, glkote_event_data)
writeBufferJSON(buffer, glkote_event_data)
})
},

emglken_send_glkote_update(update_ptr, update_len) {
const update = UTF8ToString(update_ptr, update_len)
const obj = JSON.parse(update)
const obj = JSON.parse(UTF8ToString(update_ptr, update_len))
// TODO: Store the usage of a fileref prompt request?
GlkOte.update(obj)
},

$FILETYPES: ['data', 'save', 'transcript', 'command'],

$writeBuffer(buffer, data) {
const ptr = _malloc(data.length)
HEAP8.set(data, ptr)
{{{ makeSetValue('buffer', 0, 'ptr', 'i32') }}}
{{{ makeSetValue('buffer', 4, 'data.length', 'i32') }}}
}
},

$writeBufferJSON__deps: ['$writeBuffer'],
$writeBufferJSON(buffer, data) {
const json = JSON.stringify(data)
writeBuffer(buffer, encoder.encode(json))
},
})

0 comments on commit 5ff02f7

Please sign in to comment.