Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Full TypeScript rewrite. Best type defs #651

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
f721622
phase 1: simply rename to modules -> *.ts
zardoy Nov 2, 2023
90caa81
phase 2: add typings with script & a few manual fixes, fix a few bugs
zardoy Nov 3, 2023
bb15d04
add options types, fix some missing types
zardoy Nov 3, 2023
ff4da02
fix: setblock now correctly sets initial block state when no override
zardoy Nov 4, 2023
156c82a
make commands typed, fix many bugs! improve /tp
zardoy Nov 4, 2023
ef2393f
fix tsc & use prepare for now
zardoy Nov 4, 2023
76c5626
migrate docs to jsdoc with codemod, not documented are marked as inte…
zardoy Nov 5, 2023
8a38cdb
fix: don't mutate generation options, fix storage provider is null fo…
zardoy Nov 5, 2023
8eb54af
fix tab_complete crash in post-flatenning
zardoy Nov 11, 2023
7705c79
add slash to aliases so its easier to discover them with search
zardoy Nov 9, 2023
0fc0670
allow json resolve
zardoy Jan 8, 2024
9f1fcdf
fix build
zardoy Jan 8, 2024
a6efc32
add events, fix ts build
zardoy Jan 17, 2024
0a2a798
improve many types, fix build!
zardoy Jan 17, 2024
e8df1db
try ts-standard instead
zardoy Jan 17, 2024
426969d
rename modules back to plugins
zardoy Jan 17, 2024
4fd7926
fix jsdoc newlines
zardoy Jan 17, 2024
9b5fe20
fix docs generator
zardoy Jan 17, 2024
9b2c5f6
tests should be running as before
zardoy Jan 17, 2024
184a9e6
rm old types
zardoy Jan 17, 2024
cfc3847
revert a few things...
zardoy Jan 18, 2024
4414705
partially Revert "try ts-standard instead"
zardoy Jan 18, 2024
b514e46
rm mcdata refs
zardoy Jan 18, 2024
51cceb4
revert even more things...
zardoy Jan 18, 2024
1fdc39f
finally test that it works
zardoy Jan 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ node_modules
modpePlugins/
config/settings.json
logs/
src/plugins/*
!src/plugins/README.md
src/
distTest
world/*
!world/.gitkeep
1,179 changes: 0 additions & 1,179 deletions docs/API.md

This file was deleted.

2 changes: 1 addition & 1 deletion index.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
module.exports = require('./src/index.js')
module.exports = require('./dist/index.js')
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@
"name": "flying-squid",
"description": "A minecraft server written in node.js",
"version": "1.8.0",
"main": "index.js",
"main": "dist/index.js",
"bin": "app.js",
"author": "mhsjlw <[email protected]>",
"contributors": [
{
"name": "rom1504",
"email": "[email protected]"
}
],
"bin": "app.js",
"scripts": {
"start": "tsc && node app.js",
"build": "tsc && node scripts/genTypes.mjs",
"prepare": "npm run build",
"prepublishOnly": "cp docs/README.md README.md",
"lint": "standard test/*.test.js src/**/*.js src/**/**/*.js src/*.js examples/*.js *.js",
"fix": "standard --fix test/*.test.js src/**/*.js src/**/**/*.js src/*.js examples/*.js *.js",
Expand Down Expand Up @@ -53,6 +56,7 @@
"range": "^0.0.3",
"readline": "^1.3.0",
"spiralloop": "^1.0.2",
"typed-emitter": "1.4.0",
"uuid-1345": "^1.0.1",
"vec3": "^0.1.6",
"yargs": "^17.0.1"
Expand Down
12 changes: 12 additions & 0 deletions scripts/genTypes.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//@ts-check
import fs from 'fs'

const targetFile = './dist/types.d.ts';
const plugins = fs.readdirSync('./dist/lib/plugins').filter(f => f !== 'index')
let types = ''
types = plugins.filter(module => module.endsWith('.d.ts')).map(module => `import "./lib/plugins/${module}"`).join('\n') + '\n' + types
fs.writeFileSync(targetFile, types, 'utf8')

let indexTs = fs.readFileSync('./dist/index.d.ts', 'utf8')
indexTs = `import './types';` + indexTs
fs.writeFileSync('./dist/index.d.ts', indexTs, 'utf8')
20 changes: 14 additions & 6 deletions src/globals.d.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
// make process.platform also accept browser
declare namespace NodeJS {
interface Process {
platform: string;
browser?: boolean
}
interface Process {
// @ts-expect-error
platform: string
browser?: boolean
}

}
interface NodeRequire {
// webpack bundling
context: (path: string, deep: boolean, filter: RegExp) => { keys: () => string[]; (id: string): any };
// webpack bundling
context: (path: string, deep: boolean, filter: RegExp) => { keys: () => string[], (id: string): any }
}

interface ObjectConstructor {
keys: <T extends object>(obj: T) => Array<StringKeys<T>>
entries: <T extends object>(obj: T) => Array<[StringKeys<T>, T[keyof T]]>
fromEntries: <T extends Array<[string, any]>>(obj: T) => Record<T[number][0], T[number][1]>
assign: <T extends Record<string, any>, K extends Record<string, any>>(target: T, source: K) => asserts target is T & K
}
73 changes: 0 additions & 73 deletions src/index.js

This file was deleted.

106 changes: 106 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { createServer, Server as ProtocolServer } from 'minecraft-protocol'

import { testedVersions, latestSupportedVersion, oldestSupportedVersion } from './lib/version'
import Command from './lib/command'
import * as plugins from './lib/plugins'
import { EventEmitter } from 'events'

import './modules'

// #region RUNTIME PREPARE
if (typeof process !== 'undefined' && !process.browser && process.platform !== 'browser' && parseInt(process.versions.node.split('.')[0]) < 18) {
console.error('[\x1b[31mCRITICAL\x1b[0m] Node.JS 18 or newer is required')
console.error('[\x1b[31mCRITICAL\x1b[0m] You can download the new version from https://nodejs.org/')
console.error(`[\x1b[31mCRITICAL\x1b[0m] Your current Node.JS version is: ${process.versions.node}`)
process.exit(1)
}

require('emit-then').register()
if (process.env.NODE_ENV === 'dev') {
require('longjohn')
}
// #endregion

// types

export interface FullServer extends Server { }
export interface FullPlayer extends Player { }
export interface FullEntity extends Entity { }
export interface ServerEventsMap extends ServerEvents { }
export interface PlayerEventsMap extends PlayerEvents { }
// export interface EntityEventsMap extends ServerEvents {}
export type InputOptions = Partial<Options> & Pick<Options, 'version'>

export function createMCServer (options: InputOptions): FullServer {
const mcServer = new MCServer()
mcServer.connect({
// defaults
'max-entities': 100,
...options
})
return mcServer as unknown as Server
}

class MCServer extends EventEmitter {
pluginsReady = false
_server: ProtocolServer = null!
constructor () {
plugins.initPlugins()
super()
}

connect (options) {
const server = this as unknown as Server
const registry = require('prismarine-registry')(options.version)
if (!registry?.version) throw new Error(`Server version '${registry?.version}' is not supported, no data for version`)

const versionData = registry.version
if (versionData['>'](latestSupportedVersion)) {
throw new Error(`Server version '${registry?.version}' is not supported. Latest supported version is '${latestSupportedVersion}'.`)
} else if (versionData['<'](oldestSupportedVersion)) {
throw new Error(`Server version '${registry?.version}' is not supported. Oldest supported version is '${oldestSupportedVersion}'.`)
}

server.commands = new Command({})
server._server = createServer(options)

const promises: Array<Promise<any>> = []
for (const plugin of plugins.builtinPlugins) {
promises.push(plugin.server?.(server, options))
}
Promise.all(promises).then(() => {
server.emit('pluginsReady')
server.pluginsReady = true
})

if (options.logging === true) server.createLog()
server._server.on('error', error => {
server.emit('error', error)
})
server._server.on('listening', () => {
// @ts-expect-error dont remember the right cast
server.emit('listening', server._server.socketServer.address().port)
})
server.emit('asap')
}
}

declare global {
interface Server {
commands: Command
pluginsReady: boolean
_server: ProtocolServer
supportFeature: (feature: string) => boolean
}
}

export {
testedVersions
}

export * as Behavior from './lib/behavior'
export * as Command from './lib/command'
export { default as generations } from './lib/generations'
export * as experience from './lib/experience'
export * as UserError from './lib/user_error'
export { default as portal_detector } from './lib/portal_detector'
8 changes: 3 additions & 5 deletions src/lib/behavior.js → src/lib/behavior.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module.exports = (obj) => {
return async (eventName, data, func, cancelFunc) => {
export default (obj) => {
return async (eventName: string, data?: any, func: Function = (() => { }), cancelFunc?: Function) => {
let hiddenCancelled = false
let cancelled = false
let cancelCount = 0
Expand All @@ -13,9 +13,7 @@ module.exports = (obj) => {
defaultCancel = dC
}

let resp

func = func || (() => {})
let resp!: boolean | Promise<any>

await obj.emitThen(eventName + '_cancel', data, cancel).catch((err) => setTimeout(() => { throw err }, 0))
await obj.emitThen(eventName, data, cancelled, cancelCount).catch((err) => setTimeout(() => { throw err }, 0))
Expand Down
43 changes: 34 additions & 9 deletions src/lib/command.js → src/lib/command.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,33 @@
const UserError = require('./user_error')
import UserError from './user_error'

type Ctx<P extends boolean> = P extends true ? {
player: Player
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i tried to not add a lot of generics, but this one here is just super useful for other plugins

} : {
player?: Player
}

type NonFalsey<T> = T extends false ? never : NonNullable<T>

type AddParams<T, P extends boolean = false> = {
base: string,
aliases?: string[],
info: string,
usage: string,
onlyPlayer?: P
op?: boolean
parse?: (string: string, ctx: Ctx<P>) => T
action: (data: NonFalsey<T>, ctx: Ctx<P>) => any
tab?: string[]
}

class Command {
constructor (params, parent, hash) {
this.params = params
this.parent = parent
hash: any
uniqueHash: any
parentBase: any
base: any
path: string

constructor (public params, public parent?, hash?) {
this.hash = parent ? parent.hash : {}
this.uniqueHash = parent ? parent.uniqueHash : {}
this.parentBase = (this.parent && this.parent.base && this.parent.base + ' ') || ''
Expand All @@ -20,7 +44,7 @@ class Command {
return undefined
}

async use (command, ctx = {}, op = true) {
async use (command, ctx: Ctx<false> = {}, op = true) {
const resultsFound = this.find(command)
let parsedResponse
if (resultsFound) {
Expand Down Expand Up @@ -56,7 +80,7 @@ class Command {

const list = [this.base]
if (this.params.aliases && this.params.aliases.length) {
this.params.aliases.forEach(al => list.unshift(this.parentBase + al))
this.params.aliases.forEach(al => list.unshift(this.parentBase + al.replace(/^\//, '')))
}

list.forEach((command) => {
Expand All @@ -69,11 +93,11 @@ class Command {
this.uniqueHash[this.base] = this
}

add (params) {
add <T, P extends boolean>(params: AddParams<T, P>) {
return new Command(params, this)
}

space (end) {
space (end = false) {
const first = !(this.parent && this.parent.parent)
return this.params.merged || (!end && first) ? '' : ' '
}
Expand All @@ -83,9 +107,10 @@ class Command {
}

tab (command, i) {
// @ts-expect-error
if (this.find(command)[0].params.tab) return this.find(command)[0].params.tab[i]
return 'player'
}
}

module.exports = Command
export default Command
4 changes: 2 additions & 2 deletions src/lib/convertInventorySlotId.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
module.exports = { fromNBT, toNBT }

const replace = {
100: 8, 101: 7, 102: 6, 103: 5, '-106': 45
}
Expand Down Expand Up @@ -28,3 +26,5 @@ function toNBT (slotId) {
}
return invertReplace[returnSlotId] || slot
}

export { fromNBT, toNBT }
4 changes: 2 additions & 2 deletions src/lib/experience.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
module.exports = { distanceToXpLevel, getXpLevel, getXpRequired, getBaseXpFromLevel }

function distanceToXpLevel (xp, toLevel) {
const level = getXpLevel(xp)
if (!toLevel) toLevel = level + 1
Expand Down Expand Up @@ -46,3 +44,5 @@ function getBaseXpFromLevel (level) {
return 4.5 * level * level - 162.5 * level + 2220
}
}

export { distanceToXpLevel, getXpLevel, getXpRequired, getBaseXpFromLevel }
Loading
Loading