diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..749db005 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,12 @@ +node_modules +package-lock.json +yarn.lock + +filebase +db +drop +file_base +logs +mail +docs/_site +docs/.sass-cache \ No newline at end of file diff --git a/WHATSNEW.md b/WHATSNEW.md index 0bc3688f..2ff477f4 100644 --- a/WHATSNEW.md +++ b/WHATSNEW.md @@ -16,7 +16,8 @@ This document attempts to track **major** changes and additions in ENiGMA½. For * CombatNet has shut down, so the module (`combatnet.js`) has been removed. * New `NewUserPrePersist` system event available to developers to 'hook' account creation and add their own properties/etc. * The signature for `viewValidationListener`'s callback has changed: It is now `(err, newFocusId)`. To ignore a validation error, implementors can simply call the callback with a `null` error, else they should forward it on. -* The Menu Flag `popParent` has been removed and `noHistory` has been updated to work as expected. In general things should "Just Work", but do see [UPGRADE](UPGRADE.md)! +* The Menu Flag `popParent` has been removed and `noHistory` has been updated to work as expected. In general things should "Just Work", but do see [UPGRADE](UPGRADE.md) for additional details. +* Art handling has been changed to respect the art width contained in SAUCE when present in the case where the terminal width is greater than the art width. This fixes art files that assume wrapping at 80 columns on wide (mostly new utf8) terminals. ## 0.0.13-beta * **Note for contributors**: ENiGMA has switched to [Prettier](https://prettier.io) for formatting/style. Please see [CONTRIBUTING](CONTRIBUTING.md) and the Prettier website for more information. diff --git a/core/ansi_escape_parser.js b/core/ansi_escape_parser.js index 27d5490d..d2879c21 100644 --- a/core/ansi_escape_parser.js +++ b/core/ansi_escape_parser.js @@ -37,6 +37,12 @@ function ANSIEscapeParser(options) { this.mciReplaceChar = miscUtil.valueWithDefault(options.mciReplaceChar, ''); this.termHeight = miscUtil.valueWithDefault(options.termHeight, 25); this.termWidth = miscUtil.valueWithDefault(options.termWidth, 80); + this.breakWidth = this.termWidth; + // toNumber takes care of null, undefined etc as well. + let artWidth = _.toNumber(options.artWidth); + if (!_.isNaN(artWidth) && artWidth > 0 && artWidth < this.breakWidth) { + this.breakWidth = options.artWidth; + } this.trailingLF = miscUtil.valueWithDefault(options.trailingLF, 'default'); this.row = Math.min(options?.startRow ?? 1, this.termHeight); @@ -90,8 +96,8 @@ function ANSIEscapeParser(options) { switch (charCode) { case CR: - self.emit('literal', text.slice(start, pos)); - start = pos; + self.emit('literal', text.slice(start, pos + 1)); + start = pos + 1; self.column = 1; @@ -105,8 +111,8 @@ function ANSIEscapeParser(options) { self.column = 1; } - self.emit('literal', text.slice(start, pos)); - start = pos; + self.emit('literal', text.slice(start, pos + 1)); + start = pos + 1; self.row += 1; @@ -114,13 +120,16 @@ function ANSIEscapeParser(options) { break; default: - if (self.column === self.termWidth) { + if (self.column === self.breakWidth) { self.emit('literal', text.slice(start, pos + 1)); start = pos + 1; + // If we hit breakWidth before termWidth then we need to force the terminal to go to the next line. + if (self.column < self.termWidth) { + self.emit('literal', '\r\n'); + } self.column = 1; self.row += 1; - self.positionUpdated(); } else { self.column += 1; @@ -135,7 +144,7 @@ function ANSIEscapeParser(options) { // // Finalize this chunk // - if (self.column > self.termWidth) { + if (self.column > self.breakWidth) { self.column = 1; self.row += 1; diff --git a/core/art.js b/core/art.js index 5e46591c..52e5433a 100644 --- a/core/art.js +++ b/core/art.js @@ -46,6 +46,16 @@ function getFontNameFromSAUCE(sauce) { } } +function getWidthFromSAUCE(sauce) { + if (sauce.Character) { + let sauceWidth = _.toNumber(sauce.Character.characterWidth); + if (!_.isNaN(sauceWidth) && sauceWidth > 0) { + return sauceWidth; + } + } + return null; +} + function sliceAtEOF(data, eofMarker) { let eof = data.length; const stopPos = Math.max(data.length - 256, 0); // 256 = 2 * sizeof(SAUCE) @@ -274,6 +284,7 @@ function display(client, art, options, cb) { mciReplaceChar: options.mciReplaceChar, termHeight: client.term.termHeight, termWidth: client.term.termWidth, + artWidth: getWidthFromSAUCE(options.sauce), trailingLF: options.trailingLF, startRow: options.startRow, }); diff --git a/docker/Dockerfile b/docker/Dockerfile index b53c72df..c09b7a5c 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,4 +1,4 @@ -FROM node:14-buster-slim +FROM node:18-buster-slim LABEL maintainer="dave@force9.org" @@ -21,8 +21,10 @@ RUN apt-get update \ lhasa \ unrar-free \ p7zip-full \ + dos2unix \ + && npm install -g npm@latest \ && npm install -g pm2 \ - && cd /enigma-bbs && npm install --only=production \ + && cd /enigma-bbs && npm install \ && pm2 start main.js \ && mkdir -p /enigma-bbs-pre/art \ && mkdir /enigma-bbs-pre/mods \ @@ -37,6 +39,7 @@ RUN apt-get update \ # sexyz COPY docker/bin/sexyz /usr/local/bin +RUN dos2unix /enigma-bbs/docker/bin/docker-entrypoint.sh && apt-get remove dos2unix -y RUN chmod +x /enigma-bbs/docker/bin/docker-entrypoint.sh # enigma storage mounts diff --git a/docs/_docs/installation/docker.md b/docs/_docs/installation/docker.md index a6959b81..f2f7affa 100644 --- a/docs/_docs/installation/docker.md +++ b/docs/_docs/installation/docker.md @@ -71,5 +71,9 @@ Customising the Docker image is easy! 1. Clone the ENiGMA-BBS source. 2. Build the image ```bash -docker build -f ./docker/Dockerfile . +docker build -t enigmabbs -f ./docker/Dockerfile . +``` +3. Run the image +```bash +docker run -it -p 8888:8888 --name "ENiGMABBS" -v "$(pwd)/config:/enigma-bbs/config" -v "$(pwd)/db:/enigma-bbs/db" -v "$(pwd)/logs:/enigma-bbs/logs" -v "$(pwd)/filebase:/enigma-bbs/filebase" -v "$(pwd)/art:/enigma-bbs/art" -v "$(pwd)/mods:/enigma-bbs/mods" -v "$(pwd)/mail:/mail" enigmabbs ```