1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-01-29 18:34:47 +00:00

Merge branch 'mc-1.17.x' into mc-1.18.x

This commit is contained in:
Jonathan Coates 2021-12-25 08:05:25 +00:00
commit 2b901f2d5e
No known key found for this signature in database
GPG Key ID: B9E431FF07C98D06
14 changed files with 3162 additions and 36 deletions

1
.gitattributes vendored
View File

@ -13,3 +13,4 @@ src/testMod/server-files/structures linguist-generated
*.png binary *.png binary
*.jar binary *.jar binary
*.dfpwm binary

View File

@ -290,18 +290,7 @@ task rollup(type: Exec) {
commandLine mkCommand('"node_modules/.bin/rollup" --config rollup.config.js') commandLine mkCommand('"node_modules/.bin/rollup" --config rollup.config.js')
} }
task minifyWeb(type: Exec, dependsOn: rollup) { task illuaminateDocs(type: Exec, dependsOn: [rollup, luaJavadoc]) {
group = "build"
description = "Bundles JS into rollup"
inputs.file("$buildDir/rollup/index.js").withPropertyName("sources")
inputs.file("package-lock.json").withPropertyName("package-lock.json")
outputs.file("$buildDir/rollup/index.min.js").withPropertyName("output")
commandLine mkCommand('"node_modules/.bin/terser"' + " -o '$buildDir/rollup/index.min.js' '$buildDir/rollup/index.js'")
}
task illuaminateDocs(type: Exec, dependsOn: [minifyWeb, luaJavadoc]) {
group = "build" group = "build"
description = "Bundles JS into rollup" description = "Bundles JS into rollup"
@ -309,7 +298,7 @@ task illuaminateDocs(type: Exec, dependsOn: [minifyWeb, luaJavadoc]) {
inputs.files(fileTree("src/main/resources/data/computercraft/lua/rom")).withPropertyName("lua rom") inputs.files(fileTree("src/main/resources/data/computercraft/lua/rom")).withPropertyName("lua rom")
inputs.file("illuaminate.sexp").withPropertyName("illuaminate.sexp") inputs.file("illuaminate.sexp").withPropertyName("illuaminate.sexp")
inputs.dir("$buildDir/docs/luaJavadoc") inputs.dir("$buildDir/docs/luaJavadoc")
inputs.file("$buildDir/rollup/index.min.js").withPropertyName("scripts") inputs.file("$buildDir/rollup/index.js").withPropertyName("scripts")
inputs.file("src/web/styles.css").withPropertyName("styles") inputs.file("src/web/styles.css").withPropertyName("styles")
outputs.dir("$buildDir/docs/lua") outputs.dir("$buildDir/docs/lua")
@ -317,9 +306,13 @@ task illuaminateDocs(type: Exec, dependsOn: [minifyWeb, luaJavadoc]) {
} }
task docWebsite(type: Copy, dependsOn: [illuaminateDocs]) { task docWebsite(type: Copy, dependsOn: [illuaminateDocs]) {
from 'doc' from('doc') {
include 'logo.png' include 'logo.png'
include 'images/**' include 'images/**'
}
from("$buildDir/rollup") {
exclude 'index.js'
}
into "${project.docsDir}/lua" into "${project.docsDir}/lua"
} }

View File

@ -51,5 +51,6 @@ exclude: |
src/generated| src/generated|
src/test/resources/test-rom/data/json-parsing/| src/test/resources/test-rom/data/json-parsing/|
src/testMod/server-files/| src/testMod/server-files/|
config/idea/ config/idea/|
.*\.dfpwm
) )

View File

@ -12,7 +12,7 @@ see: speaker.playAudio To play audio using the speaker
This uses @{io.lines} to read audio data in blocks of 16KiB from "example_song.dfpwm", and then attempts to play it This uses @{io.lines} to read audio data in blocks of 16KiB from "example_song.dfpwm", and then attempts to play it
using @{speaker.playAudio}. If the speaker's buffer is full, it waits for an event and tries again. using @{speaker.playAudio}. If the speaker's buffer is full, it waits for an event and tries again.
```lua ```lua {data-peripheral=speaker}
local dfpwm = require("cc.audio.dfpwm") local dfpwm = require("cc.audio.dfpwm")
local speaker = peripheral.find("speaker") local speaker = peripheral.find("speaker")

View File

@ -145,7 +145,7 @@ adds the sample from one second ago to it.
For this, we'll need to keep track of the last 48k samples - exactly one seconds worth of audio. We can do this using a For this, we'll need to keep track of the last 48k samples - exactly one seconds worth of audio. We can do this using a
[Ring Buffer], which helps makes things a little more efficient. [Ring Buffer], which helps makes things a little more efficient.
```lua ```lua {data-peripheral=speaker}
local dfpwm = require("cc.audio.dfpwm") local dfpwm = require("cc.audio.dfpwm")
local speaker = peripheral.find("speaker") local speaker = peripheral.find("speaker")
@ -157,14 +157,14 @@ for i = 1, samples_n do samples[i] = 0 end
local decoder = dfpwm.make_decoder() local decoder = dfpwm.make_decoder()
for chunk in io.lines("data/example.dfpwm", 16 * 1024) do for chunk in io.lines("data/example.dfpwm", 16 * 1024) do
local buffer = decoder(input) local buffer = decoder(chunk)
for i = 1, #buffer do for i = 1, #buffer do
local original_value = buffer[i] local original_value = buffer[i]
-- Replace this sample with its current amplitude plus the amplitude from one second ago. -- Replace this sample with its current amplitude plus the amplitude from one second ago.
-- We scale both to ensure the resulting value is still between -128 and 127. -- We scale both to ensure the resulting value is still between -128 and 127.
buffer[i] = original_value * 0.7 + samples[samples_i] * 0.3 buffer[i] = original_value * 0.6 + samples[samples_i] * 0.4
-- Now store the current sample, and move the "head" of our ring buffer forward one place. -- Now store the current sample, and move the "head" of our ring buffer forward one place.
samples[samples_i] = original_value samples[samples_i] = original_value

86
package-lock.json generated
View File

@ -14,6 +14,7 @@
}, },
"devDependencies": { "devDependencies": {
"@rollup/plugin-typescript": "^8.2.5", "@rollup/plugin-typescript": "^8.2.5",
"@rollup/plugin-url": "^6.1.0",
"requirejs": "^2.3.6", "requirejs": "^2.3.6",
"rollup": "^2.33.1", "rollup": "^2.33.1",
"rollup-plugin-terser": "^7.0.2", "rollup-plugin-terser": "^7.0.2",
@ -73,6 +74,23 @@
"typescript": ">=3.7.0" "typescript": ">=3.7.0"
} }
}, },
"node_modules/@rollup/plugin-url": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/@rollup/plugin-url/-/plugin-url-6.1.0.tgz",
"integrity": "sha512-FJNWBnBB7nLzbcaGmu1no+U/LlRR67TtgfRFP+VEKSrWlDTE6n9jMns/N4Q/VL6l4x6kTHQX4HQfwTcldaAfHQ==",
"dev": true,
"dependencies": {
"@rollup/pluginutils": "^3.1.0",
"make-dir": "^3.1.0",
"mime": "^2.4.6"
},
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"rollup": "^1.20.0||^2.0.0"
}
},
"node_modules/@rollup/pluginutils": { "node_modules/@rollup/pluginutils": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz",
@ -264,12 +282,39 @@
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"dev": true "dev": true
}, },
"node_modules/make-dir": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
"integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
"dev": true,
"dependencies": {
"semver": "^6.0.0"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/merge-stream": { "node_modules/merge-stream": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
"dev": true "dev": true
}, },
"node_modules/mime": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz",
"integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==",
"dev": true,
"bin": {
"mime": "cli.js"
},
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/path-parse": { "node_modules/path-parse": {
"version": "1.0.7", "version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
@ -382,6 +427,15 @@
} }
] ]
}, },
"node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"dev": true,
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/serialize-javascript": { "node_modules/serialize-javascript": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
@ -512,6 +566,17 @@
"resolve": "^1.17.0" "resolve": "^1.17.0"
} }
}, },
"@rollup/plugin-url": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/@rollup/plugin-url/-/plugin-url-6.1.0.tgz",
"integrity": "sha512-FJNWBnBB7nLzbcaGmu1no+U/LlRR67TtgfRFP+VEKSrWlDTE6n9jMns/N4Q/VL6l4x6kTHQX4HQfwTcldaAfHQ==",
"dev": true,
"requires": {
"@rollup/pluginutils": "^3.1.0",
"make-dir": "^3.1.0",
"mime": "^2.4.6"
}
},
"@rollup/pluginutils": { "@rollup/pluginutils": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz",
@ -665,12 +730,27 @@
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"dev": true "dev": true
}, },
"make-dir": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
"integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
"dev": true,
"requires": {
"semver": "^6.0.0"
}
},
"merge-stream": { "merge-stream": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
"dev": true "dev": true
}, },
"mime": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz",
"integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==",
"dev": true
},
"path-parse": { "path-parse": {
"version": "1.0.7", "version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
@ -740,6 +820,12 @@
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"dev": true "dev": true
}, },
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"dev": true
},
"serialize-javascript": { "serialize-javascript": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",

View File

@ -10,6 +10,7 @@
}, },
"devDependencies": { "devDependencies": {
"@rollup/plugin-typescript": "^8.2.5", "@rollup/plugin-typescript": "^8.2.5",
"@rollup/plugin-url": "^6.1.0",
"requirejs": "^2.3.6", "requirejs": "^2.3.6",
"rollup": "^2.33.1", "rollup": "^2.33.1",
"rollup-plugin-terser": "^7.0.2", "rollup-plugin-terser": "^7.0.2",

View File

@ -1,7 +1,8 @@
import { readFileSync } from "fs"; import { readFileSync } from "fs";
import path from "path"; import path from "path";
import typescript from "@rollup/plugin-typescript"; import typescript from "@rollup/plugin-typescript";
import url from '@rollup/plugin-url';
import { terser } from "rollup-plugin-terser"; import { terser } from "rollup-plugin-terser";
const input = "src/web"; const input = "src/web";
@ -10,7 +11,7 @@ const requirejs = readFileSync("node_modules/requirejs/require.js");
export default { export default {
input: [`${input}/index.tsx`], input: [`${input}/index.tsx`],
output: { output: {
file: "build/rollup/index.js", dir: "build/rollup/",
// We bundle requirejs (and config) into the header. It's rather gross // We bundle requirejs (and config) into the header. It's rather gross
// but also works reasonably well. // but also works reasonably well.
// Also suffix a ?v=${date} onto the end in the event we need to require a specific copy-cat version. // Also suffix a ?v=${date} onto the end in the event we need to require a specific copy-cat version.
@ -18,7 +19,7 @@ export default {
${requirejs} ${requirejs}
require.config({ require.config({
paths: { copycat: "https://copy-cat.squiddev.cc" }, paths: { copycat: "https://copy-cat.squiddev.cc" },
urlArgs: function(id) { return id == "copycat/embed" ? "?v=20211127" : ""; } urlArgs: function(id) { return id == "copycat/embed" ? "?v=20211221" : ""; }
}); });
`, `,
format: "amd", format: "amd",
@ -33,12 +34,18 @@ export default {
plugins: [ plugins: [
typescript(), typescript(),
url({
include: "**/*.dfpwm",
fileName: "[name]-[hash][extname]",
publicPath: "/",
}),
{ {
name: "cc-tweaked", name: "cc-tweaked",
async transform(code, file) { async transform(code, file) {
// Allow loading files in /mount. // Allow loading files in /mount.
const ext = path.extname(file); const ext = path.extname(file);
return ext != '.tsx' && ext != '.ts' && path.dirname(file) === path.resolve(`${input}/mount`) return ext != '.dfpwm' && path.dirname(file) === path.resolve(`${input}/mount`)
? `export default ${JSON.stringify(code)};\n` ? `export default ${JSON.stringify(code)};\n`
: null; : null;
}, },

View File

@ -143,14 +143,14 @@ streams, or use different decoders for the same stream, the resulting audio may
@usage Reads "data/example.dfpwm" in blocks of 16KiB (the speaker can accept a maximum of 128×1024 samples), decodes @usage Reads "data/example.dfpwm" in blocks of 16KiB (the speaker can accept a maximum of 128×1024 samples), decodes
them and then plays them through the speaker. them and then plays them through the speaker.
```lua ```lua {data-peripheral=speaker}
local dfpwm = require "cc.audio.dfpwm" local dfpwm = require "cc.audio.dfpwm"
local speaker = peripheral.find("speaker") local speaker = peripheral.find("speaker")
local decoder = dfpwm.make_decoder() local decoder = dfpwm.make_decoder()
for input in io.lines("data/example.dfpwm", 16 * 1024 * 2) do for input in io.lines("data/example.dfpwm", 16 * 1024) do
local decoded = decoder(input) local decoded = decoder(input)
while not speaker.playAudio(output) do while not speaker.playAudio(decoded) do
os.pullEvent("speaker_audio_empty") os.pullEvent("speaker_audio_empty")
end end
end end

View File

@ -1,4 +1,4 @@
import { render, h, Component, Computer } from "copycat/embed"; import { render, h, Component, Computer, PeripheralKind } from "copycat/embed";
import type { ComponentChild } from "preact"; import type { ComponentChild } from "preact";
import settingsFile from "./mount/.settings"; import settingsFile from "./mount/.settings";
@ -6,6 +6,8 @@ import startupFile from "./mount/startup.lua";
import exprTemplate from "./mount/expr_template.lua"; import exprTemplate from "./mount/expr_template.lua";
import exampleNfp from "./mount/example.nfp"; import exampleNfp from "./mount/example.nfp";
import exampleNft from "./mount/example.nft"; import exampleNft from "./mount/example.nft";
import exampleAudioLicense from "./mount/example.dfpwm.LICENSE";
import exampleAudioUrl from "./mount/example.dfpwm";
const defaultFiles: { [filename: string]: string } = { const defaultFiles: { [filename: string]: string } = {
".settings": settingsFile, ".settings": settingsFile,
@ -21,13 +23,23 @@ const clamp = (value: number, min: number, max: number): number => {
return value; return value;
} }
const download = async (url: string): Promise<Uint8Array> => {
const result = await fetch(url);
if (result.status != 200) throw new Error(`${url} responded with ${result.status} ${result.statusText}`);
return new Uint8Array(await result.arrayBuffer());
};
let dfpwmAudio: Promise<Uint8Array> | null = null;
const Click = (options: { run: () => void }) => const Click = (options: { run: () => void }) =>
<button type="button" class="example-run" onClick={options.run}>Run </button> <button type="button" class="example-run" onClick={options.run}>Run </button>
type WindowProps = {}; type WindowProps = {};
type Example = { type Example = {
files: { [file: string]: string }, files: { [file: string]: string | Uint8Array },
peripheral: PeripheralKind | null,
} }
type WindowState = { type WindowState = {
@ -69,7 +81,8 @@ class Window extends Component<WindowProps, WindowState> {
} }
const mount = element.getAttribute("data-mount"); const mount = element.getAttribute("data-mount");
render(<Click run={this.runExample(example, mount)} />, element); const peripheral = element.getAttribute("data-peripheral");
render(<Click run={this.runExample(example, mount, peripheral)} />, element);
} }
} }
@ -86,20 +99,20 @@ class Window extends Component<WindowProps, WindowState> {
<div class="computer-container"> <div class="computer-container">
<Computer key={exampleIdx} files={{ <Computer key={exampleIdx} files={{
...example!.files, ...defaultFiles ...example!.files, ...defaultFiles
}} /> }} peripherals={{ back: example!.peripheral }} />
</div> </div>
</div> : <div class="example-window example-window-hidden" />; </div> : <div class="example-window example-window-hidden" />;
} }
private runExample(example: string, mount: string | null): () => void { private runExample(example: string, mount: string | null, peripheral: string | null): () => void {
return () => { return async () => {
if (!this.positioned) { if (!this.positioned) {
this.positioned = true; this.positioned = true;
this.left = 20; this.left = 20;
this.top = 20; this.top = 20;
} }
const files: { [file: string]: string } = { "example.lua": example }; const files: { [file: string]: string | Uint8Array } = { "example.lua": example };
if (mount !== null) { if (mount !== null) {
for (const toMount of mount.split(",")) { for (const toMount of mount.split(",")) {
const [name, path] = toMount.split(":", 2); const [name, path] = toMount.split(":", 2);
@ -107,9 +120,23 @@ class Window extends Component<WindowProps, WindowState> {
} }
} }
if (example.includes("data/example.dfpwm")) {
files["data/example.dfpwm.LICENSE"] = exampleAudioLicense;
try {
if (dfpwmAudio === null) dfpwmAudio = download(exampleAudioUrl);
files["data/example.dfpwm"] = await dfpwmAudio;
} catch (e) {
console.error("Cannot download example dfpwm", e);
}
}
this.setState(({ exampleIdx }: WindowState) => ({ this.setState(({ exampleIdx }: WindowState) => ({
visible: true, visible: true,
example: { files }, example: {
files,
peripheral: peripheral as PeripheralKind | null,
},
exampleIdx: exampleIdx + 1, exampleIdx: exampleIdx + 1,
})); }));
} }

2982
src/web/mount/example.dfpwm Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,3 @@
Playing Soliloquy [Remake] by Alcakight
Source: https://soundcloud.com/alcaknight/soliloquy-remake
License: under CC BY 3.0

View File

@ -1,3 +1,12 @@
-- Print out license information if needed
if fs.exists("data/example.dfpwm") then
local h = io.open("data/example.dfpwm.LICENSE")
local contents = h:read("*a")
h:close()
write(contents)
end
-- Make the startup file invisible, then run the file. We could use -- Make the startup file invisible, then run the file. We could use
-- shell.run, but this ensures the program is in shell history, etc... -- shell.run, but this ensures the program is in shell history, etc...
fs.delete("startup.lua") fs.delete("startup.lua")

View File

@ -19,10 +19,23 @@ declare module "*.settings" {
export default contents; export default contents;
} }
declare module "*.LICENSE" {
const contents: string;
export default contents;
}
declare module "*.dfpwm" {
const contents: string;
export default contents;
}
declare module "copycat/embed" { declare module "copycat/embed" {
import { h, Component, render, ComponentChild } from "preact"; import { h, Component, render, ComponentChild } from "preact";
export type Side = "up" | "down" | "left" | "right" | "front" | "back";
export type PeripheralKind = "speaker";
export { h, Component, render }; export { h, Component, render };
export type ComputerAccess = unknown; export type ComputerAccess = unknown;
@ -35,6 +48,9 @@ declare module "copycat/embed" {
width?: number, width?: number,
height?: number, height?: number,
resolve?: (computer: ComputerAccess) => void, resolve?: (computer: ComputerAccess) => void,
peripherals?: {
[side in Side]?: PeripheralKind | null
},
} }
class Computer extends Component<MainProps, unknown> { class Computer extends Component<MainProps, unknown> {