Skip to content

Instantly share code, notes, and snippets.

@sminnee
Last active October 4, 2021 20:30
Show Gist options
  • Save sminnee/1d4d2bea8d909fb62e7a94c99def79fb to your computer and use it in GitHub Desktop.
Save sminnee/1d4d2bea8d909fb62e7a94c99def79fb to your computer and use it in GitHub Desktop.
diff --git a/common/messages/grid.ts b/common/messages/grid.ts
index 155e77fd..54ad174c 100644
--- a/common/messages/grid.ts
+++ b/common/messages/grid.ts
@@ -1,70 +1,86 @@
// Descriptions used in message types
+import * as t from 'io-ts'
import { TDate } from 'timeago.js'
+import { User } from '../../src/user'
import { FeatureDescription } from './feature'
export type ParcelAuthResult = 'Owner' | 'Collaborator' | 'Sandbox' | 'Moderator' | 'Tower Owner' | false
-export enum LightmapStatus {
- None = 'None',
- Requested = 'Requested',
- Baking = 'Baking',
- Baked = 'Baked',
- Failed = 'Failed',
- HashMismatch = 'HashMismatch',
-}
-
-export type ParcelRef = {
- id: number
- owner: string
- name?: string
- description?: string
- hash?: string
- island?: string
- suburb?: string
- contributors?: string[]
- grid?: boolean
- sandbox?: boolean
-
- // todo: please nerf
- lightmap_status?: LightmapStatus
-}
-
-export type ParcelGeometry = {
- type: 'Polygon'
- crs: {
- type: 'name'
- properties: {
- name: string
- }
- coordinates: number[][][]
- }
-}
+// export enum LightmapStatus {
+// None = 'None',
+// Requested = 'Requested',
+// Baking = 'Baking',
+// Baked = 'Baked',
+// Failed = 'Failed',
+// HashMismatch = 'HashMismatch',
+// }
+
+export const LightmapStatus = t.union([t.literal('None'), t.literal('Requested'), t.literal('Baking'), t.literal('Baked'), t.literal('Failed'), t.literal('HashMismatch')])
+export type LightmapStatus = t.TypeOf<typeof LightmapStatus>
+
+export const ParcelRef = t.intersection([
+ t.type({
+ id: t.number,
+ owner: t.string,
+ }),
+ t.partial({
+ name: t.string,
+ description: t.string,
+ hash: t.string,
+ island: t.string,
+ suburb: t.string,
+ contributors: t.array(t.string),
+ grid: t.boolean,
+ sandbox: t.boolean,
+
+ // todo: please nerf
+ lightmap_status: LightmapStatus,
+ }),
+])
+export type ParcelRef = t.TypeOf<typeof ParcelRef>
+
+export const ParcelGeometry = t.type({
+ type: t.literal('Polygon'),
+ crs: t.type({
+ type: t.literal('name'),
+ properties: t.type({
+ name: t.string,
+ }),
+ coordinates: t.array(t.array(t.array(t.number))),
+ }),
+})
+export type ParcelGeometry = t.TypeOf<typeof ParcelGeometry>
// Used in /api/parcels/cached.json
-export type ParcelDescription = ParcelRef & {
- x1: number
- x2: number
- y1: number
- y2: number
- z1: number
- z2: number
-
- address?: string
- geometry?: ParcelGeometry
- area?: number
- height?: number
- distance?: number
- price?: number
-
- // unsure
- space?: number
- scripting?: boolean
- voxels?: string
- tileset?: string
- palette?: string[]
- features?: FeatureDescription
-}
+export const ParcelDescription = t.intersection([
+ ParcelRef,
+ t.type({
+ x1: t.number,
+ x2: t.number,
+ y1: t.number,
+ y2: t.number,
+ z1: t.number,
+ z2: t.number,
+ }),
+ t.partial({
+ address: t.string,
+ geometry: ParcelGeometry,
+ area: t.number,
+ height: t.number,
+ distance: t.number,
+ price: t.number,
+
+ // unsure
+ space: t.number,
+ scripting: t.boolean,
+ voxels: t.string,
+ tileset: t.string,
+ palette: t.array(t.string),
+ //features: FeatureDescription,
+ }),
+])
+export type ParcelDescription = t.TypeOf<typeof ParcelDescription>
// Messsage types
diff --git a/package-lock.json b/package-lock.json
index 0eae7159..048cd55f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -59,6 +59,7 @@
"express-http-proxy": "1.6.0",
"express-prom-bundle": "^6.3.6",
"express-rate-limit": "^5.3.0",
+ "fp-ts": "^2.11.4",
"genversion": "^3.0.0",
"gif.js": "0.2.0",
"gifuct-js": "^2.1.1",
@@ -69,6 +70,7 @@
"https-browserify": "^1.0.0",
"ics": "^2.27.0",
"ifdef-loader": "^2.3.0",
+ "io-ts": "^2.2.16",
"isomorphic-unfetch": "^3.1.0",
"js-cookie": "2.2.0",
"jsdom": "16.4.0",
@@ -8499,6 +8501,11 @@
"node": ">= 0.6"
}
},
+ "node_modules/fp-ts": {
+ "version": "2.11.4",
+ "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-2.11.4.tgz",
+ "integrity": "sha512-lhV7tGEbs2qoVw4vmqOovChS7CAoIYU0gdiPEF8Vc4bLZct+PAMMeXrCqRyBNEo33XOvwvAmFDEDIrHPWH2/fg=="
+ },
"node_modules/fragment-cache": {
"version": "0.2.1",
"integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
@@ -9579,6 +9586,14 @@
"node": ">=4"
}
},
+ "node_modules/io-ts": {
+ "version": "2.2.16",
+ "resolved": "https://registry.npmjs.org/io-ts/-/io-ts-2.2.16.tgz",
+ "integrity": "sha512-y5TTSa6VP6le0hhmIyN0dqEXkrZeJLeC5KApJq6VLci3UEKF80lZ+KuoUs02RhBxNWlrqSNxzfI7otLX1Euv8Q==",
+ "peerDependencies": {
+ "fp-ts": "^2.5.0"
+ }
+ },
"node_modules/iota-array": {
"version": "1.0.0",
"integrity": "sha1-ge9X/l0FgUzVjCSDYyqZwwoOgIc="
@@ -25296,6 +25311,11 @@
"version": "0.1.2",
"integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
},
+ "fp-ts": {
+ "version": "2.11.4",
+ "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-2.11.4.tgz",
+ "integrity": "sha512-lhV7tGEbs2qoVw4vmqOovChS7CAoIYU0gdiPEF8Vc4bLZct+PAMMeXrCqRyBNEo33XOvwvAmFDEDIrHPWH2/fg=="
+ },
"fragment-cache": {
"version": "0.2.1",
"integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
@@ -26144,6 +26164,12 @@
"integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==",
"dev": true
},
+ "io-ts": {
+ "version": "2.2.16",
+ "resolved": "https://registry.npmjs.org/io-ts/-/io-ts-2.2.16.tgz",
+ "integrity": "sha512-y5TTSa6VP6le0hhmIyN0dqEXkrZeJLeC5KApJq6VLci3UEKF80lZ+KuoUs02RhBxNWlrqSNxzfI7otLX1Euv8Q==",
+ "requires": {}
+ },
"iota-array": {
"version": "1.0.0",
"integrity": "sha1-ge9X/l0FgUzVjCSDYyqZwwoOgIc="
diff --git a/package.json b/package.json
index 41566e4d..d61120f4 100644
--- a/package.json
+++ b/package.json
@@ -113,6 +113,7 @@
"express-http-proxy": "1.6.0",
"express-prom-bundle": "^6.3.6",
"express-rate-limit": "^5.3.0",
+ "fp-ts": "^2.11.4",
"genversion": "^3.0.0",
"gif.js": "0.2.0",
"gifuct-js": "^2.1.1",
@@ -123,6 +124,7 @@
"https-browserify": "^1.0.0",
"ics": "^2.27.0",
"ifdef-loader": "^2.3.0",
+ "io-ts": "^2.2.16",
"isomorphic-unfetch": "^3.1.0",
"js-cookie": "2.2.0",
"jsdom": "16.4.0",
diff --git a/server/grid-socket.ts b/server/grid-socket.ts
index 73a995d8..526a2513 100644
--- a/server/grid-socket.ts
+++ b/server/grid-socket.ts
@@ -109,7 +109,7 @@ class PatchSet {
}
// clear out the existing lightmap on change
- parcel.lightmap_status = LightmapStatus.None
+ parcel.lightmap_status = 'None'
// If shouldUpdateParcelScript is already true, no need to re-update it.
shouldUpdateParcelScript = shouldUpdateParcelScript ? shouldUpdateParcelScript : hasScript(patch)
@@ -547,7 +547,7 @@ export default class GridSocket {
return
}
- const hadLightmap = parcel.lightmap_status !== LightmapStatus.None
+ const hadLightmap = parcel.lightmap_status !== 'None'
ws.patches.add(msg)
@@ -556,7 +556,7 @@ export default class GridSocket {
if (hadLightmap) {
// Changes to a parcel will invalidate the lightmap, however the user won't know this has happened unless they refresh.
// This sends the message out immediately so that all clients (including builder) see the lightmap change immediately.
- this.sendLightmapStatus(msg.parcelId, parcel.hash, LightmapStatus.None)
+ this.sendLightmapStatus(msg.parcelId, parcel.hash, 'None')
}
}
@@ -625,11 +625,11 @@ export default class GridSocket {
if (authResult) {
if (msg.requestBake) {
- this.updateAndSendLightmapStatus(msg.parcelId, LightmapStatus.Requested)
+ this.updateAndSendLightmapStatus(msg.parcelId, 'Requested')
parcel.cancelBake()
parcel.requestBake()
} else if (msg.cancelBake) {
- this.updateAndSendLightmapStatus(msg.parcelId, LightmapStatus.None)
+ this.updateAndSendLightmapStatus(msg.parcelId, 'None')
parcel.cancelBake()
}
}
diff --git a/server/server.ts b/server/server.ts
index 853db8de..6c814402 100644
--- a/server/server.ts
+++ b/server/server.ts
@@ -744,8 +744,8 @@ app.get('/api/jobs/bake', cache(false), async (req: any, res: any) => {
await db.query(`update jobs set processed_at = now() where id = $1`, [job.id])
let parcel = await Parcel.load(job.parcel_id)
- if (parcel && parcel.lightmap_status !== LightmapStatus.None) {
- gridSocket.updateAndSendLightmapStatus(job.parcel_id, LightmapStatus.Baking)
+ if (parcel && parcel.lightmap_status !== 'None') {
+ gridSocket.updateAndSendLightmapStatus(job.parcel_id, 'Baking')
}
}
@@ -782,18 +782,18 @@ app.post('/api/jobs/baked', async (req: any, res: any) => {
if (success !== false) {
// only update the bake status if it hasn't been cancelled and not out of date
- if (parcel && parcel.lightmap_status === LightmapStatus.Baking && parcel.hash === hash) {
- const clientCount = gridSocket.updateAndSendLightmapStatus(parcel_id, LightmapStatus.Baked)
+ if (parcel && parcel.lightmap_status === 'Baking' && parcel.hash === hash) {
+ const clientCount = gridSocket.updateAndSendLightmapStatus(parcel_id, 'Baked')
res.status(200).send({ success: true, message: `Notified ${clientCount} clients` })
- } else if (parcel && parcel.lightmap_status !== LightmapStatus.Baking) {
- const clientCount = gridSocket.updateAndSendLightmapStatus(parcel_id, LightmapStatus.Failed)
+ } else if (parcel && parcel.lightmap_status !== 'Baking') {
+ const clientCount = gridSocket.updateAndSendLightmapStatus(parcel_id, 'Failed')
res.status(200).send({ success: true, message: `Parcel bake response discarded due to not being in "baking" state, notified ${clientCount} clients` })
} else if (parcel && parcel.hash !== hash) {
- const clientCount = gridSocket.updateAndSendLightmapStatus(parcel_id, LightmapStatus.HashMismatch)
+ const clientCount = gridSocket.updateAndSendLightmapStatus(parcel_id, 'HashMismatch')
res.status(200).send({ success: true, message: `Parcel bake response discarded due to parcel hash mismatch, notified ${clientCount} clients` })
}
} else {
- let clientCount = gridSocket.updateAndSendLightmapStatus(parcel_id, LightmapStatus.Failed)
+ let clientCount = gridSocket.updateAndSendLightmapStatus(parcel_id, 'Failed')
res.status(200).send({ success: true, message: `Notified ${clientCount} clients` })
}
})
diff --git a/src/grid.ts b/src/grid.ts
index aef94cbe..b1ff4163 100644
--- a/src/grid.ts
+++ b/src/grid.ts
@@ -314,8 +314,8 @@ export default class Grid extends SocketClient {
updateParcelLightmapStatus(parcel: any, status: LightmapStatus) {
if (parcel.lightmap_status !== status) {
- let wasBaked = parcel.lightmap_status === LightmapStatus.Baked
- let hasBake = status === LightmapStatus.Baked
+ let wasBaked = parcel.lightmap_status === 'Baked'
+ let hasBake = status === 'Baked'
parcel.updateLightmapStatus(status as LightmapStatus)
if (wasBaked !== hasBake) {
parcel.generate()
@@ -661,7 +661,7 @@ export default class Grid extends SocketClient {
p.loaded = false
// do the baked meshing on main thread if parcel has lightmap
// fixme: do baked meshing on worker thread
- if (p.lightmap_status === LightmapStatus.Baked) {
+ if (p.lightmap_status === 'Baked') {
p.generate()
}
})
diff --git a/src/parcel.ts b/src/parcel.ts
index cf58ce9f..4baaad26 100644
--- a/src/parcel.ts
+++ b/src/parcel.ts
@@ -256,15 +256,15 @@ export default class Parcel extends EventEmitter implements VoxelObject {
requestBake() {
if (this.canEdit) {
- this.updateLightmapStatus(LightmapStatus.Requested)
+ this.updateLightmapStatus('Requested')
this.connector.grid.requestBake(this.id)
}
}
cancelBake() {
if (this.canEdit) {
- let needsGenerate = this.lightmap_status === LightmapStatus.Baked
- this.updateLightmapStatus(LightmapStatus.None)
+ let needsGenerate = this.lightmap_status === 'Baked'
+ this.updateLightmapStatus('None')
this.connector.grid.cancelBake(this.id)
if (needsGenerate) {
this.generate()
@@ -289,7 +289,7 @@ export default class Parcel extends EventEmitter implements VoxelObject {
this.contributors = meta.contributors || []
this.grid = meta.grid || false
this.sandbox = meta.sandbox || false
- this.lightmap_status = meta.lightmap_status || LightmapStatus.None
+ this.lightmap_status = meta.lightmap_status || 'None'
}
receivePatch(patch: any) {
@@ -822,7 +822,7 @@ export default class Parcel extends EventEmitter implements VoxelObject {
}
async populateVoxelField(data: any) {
- if (this.lightmap_status !== LightmapStatus.Baked) {
+ if (this.lightmap_status !== 'Baked') {
// accept the grid-workers mesh only if we don't have an active lightmap
await VoxelField.generate(this, data, this.configureVoxelFieldMeshes.bind(this))
this.loaded = true
@@ -834,7 +834,7 @@ export default class Parcel extends EventEmitter implements VoxelObject {
}
async generateVoxelField() {
- if (this.lightmap_status !== LightmapStatus.Baked) {
+ if (this.lightmap_status !== 'Baked') {
// clean up the baked mesh if we are now rendering AO
if (this.voxelMesh && this.voxelMesh.name === generateVoxelOpaqueMeshName(this.id)) {
this.voxelMesh.dispose()
@@ -968,10 +968,10 @@ export default class Parcel extends EventEmitter implements VoxelObject {
clearTimeout(this.fieldUpdateTimeout)
this.fieldUpdateTimeout = setTimeout(() => {
- if (this.lightmap_status !== LightmapStatus.None) {
+ if (this.lightmap_status !== 'None') {
// force the parcel to become unbaked without waiting for the socket to tell us
// this prevents errors being thrown when building in a bake parcel while we wait for the message to come back (latency)
- this.updateLightmapStatus(LightmapStatus.None)
+ this.updateLightmapStatus('None')
}
this.voxels = this.field ? getVoxelsFromBuffer(this.field.data.buffer) : undefined
this.sendField()
diff --git a/src/ui/overlay/edit-tab.tsx b/src/ui/overlay/edit-tab.tsx
index fa556eba..8012d111 100644
--- a/src/ui/overlay/edit-tab.tsx
+++ b/src/ui/overlay/edit-tab.tsx
@@ -26,7 +26,7 @@ export default class EditTab extends Component<Props, any> {
this.state = {
brightness: props.parcel?.brightness,
- lightmapStatus: LightmapStatus.None,
+ lightmapStatus: 'None',
uploading: false,
}
}
@@ -98,11 +98,11 @@ export default class EditTab extends Component<Props, any> {
return <div />
}
- let pendingBake = this.state.lightmapStatus === LightmapStatus.Requested || this.state.lightmapStatus === LightmapStatus.Baking
- let baked = this.state.lightmapStatus === LightmapStatus.Baked
- let bakeStatusText = this.state.lightmapStatus === LightmapStatus.Requested ? 'Waiting in queue...' : 'Baking lightmap...'
- let bakeFailed = this.state.lightmapStatus === LightmapStatus.Failed
- let bakeHashMismatch = this.state.lightmapStatus === LightmapStatus.HashMismatch
+ let pendingBake = this.state.lightmapStatus === 'Requested' || this.state.lightmapStatus === 'Baking'
+ let baked = this.state.lightmapStatus === 'Baked'
+ let bakeStatusText = this.state.lightmapStatus === 'Requested' ? 'Waiting in queue...' : 'Baking lightmap...'
+ let bakeFailed = this.state.lightmapStatus === 'Failed'
+ let bakeHashMismatch = this.state.lightmapStatus === 'HashMismatch'
return (
<section className="tile-selector">
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment