@inglorious/engine
Version:
A JavaScript game engine written with global state, immutability, and pure functions in mind. Have fun(ctional programming) with it!
123 lines (104 loc) • 3.44 kB
JavaScript
import { coreEvents } from "./core-events.js"
const LAST_STATE = 1
let devToolsInstance = null
let unsubscribe = null
export function initDevTools(store) {
// Prevent multiple connections
if (devToolsInstance) {
return
}
if (typeof window === "undefined" || !window.__REDUX_DEVTOOLS_EXTENSION__) {
return
}
devToolsInstance = window.__REDUX_DEVTOOLS_EXTENSION__.connect({
name: "Inglorious Engine",
predicate: (state, action) => !coreEvents.includes(action.type),
actionCreators: {
jump: () => ({ type: "jump", payload: { inputId: "input0" } }),
},
// @see https://github.com/reduxjs/redux-devtools/blob/main/extension/docs/API/Arguments.md#features
features: {
pause: true, // start/pause recording of dispatched actions
lock: true, // lock/unlock dispatching actions and side effects
persist: true, // persist states on page reloading
export: true, // export history of actions in a file
import: "custom", // import history of actions from a file
jump: false, // jump back and forth (time travelling)
skip: false, // skip (cancel) actions
reorder: false, // drag and drop actions in the history list
dispatch: true, // dispatch custom actions or action creators
test: false, // generate tests for the selected actions
},
})
unsubscribe = devToolsInstance.subscribe((message) => {
switch (message.type) {
case "DISPATCH":
handleDispatch(message, store)
break
case "ACTION":
handleAction(message, store)
break
}
})
devToolsInstance.init(store.getState())
}
export function disconnectDevTools() {
// The `disconnect` method on the devToolsInstance is not available in all
// environments or versions of the extension.
// The safest way to "disconnect" is to unsubscribe from any listeners
// and release our reference to the instance, which prevents any further
// actions from being sent.
if (unsubscribe) {
unsubscribe()
unsubscribe = null
devToolsInstance = null
}
}
export function sendAction(action, state) {
if (devToolsInstance) {
devToolsInstance.send(action, state)
}
}
function handleDispatch(message, store) {
switch (message.payload.type) {
// reset button
case "RESET": {
store.reset()
devToolsInstance.init(store.getState())
break
}
// revert button
case "ROLLBACK": {
const newState = JSON.parse(message.state)
store.setState(newState)
break
}
// commit button
case "COMMIT": {
devToolsInstance.init(store.getState())
break
}
// import from file button
case "IMPORT_STATE": {
const { computedStates, actionsById } = message.payload.nextLiftedState
const [firstComputedState] = computedStates
const lastComputedState =
computedStates[computedStates.length - LAST_STATE]
if (lastComputedState) {
store.setState(lastComputedState.state)
}
const flattenedActions = Object.values(actionsById)
.flatMap(({ action }) => action.payload ?? action)
.map((action, index) => [index, action])
devToolsInstance.init(
firstComputedState.state,
Object.fromEntries(flattenedActions),
)
break
}
}
}
function handleAction(message, store) {
const action = JSON.parse(message.payload)
store.dispatch(action)
}