HMR for blockly blocks
This commit is contained in:
@@ -18,7 +18,7 @@ export const GameObjectView = observer(function (props: GameObjectViewProps) {
|
||||
return <PlayerObjectView object={props.object as RuntimeGameObjectInstance} objectType={objectType} />;
|
||||
|
||||
function handleClick(): void {
|
||||
state.game?.emitEvent('object_clicked', { object: props.object });
|
||||
state.game?.emitEvent('objectClicked', { object: props.object });
|
||||
}
|
||||
|
||||
return <ObjectViewInternal
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { ObjectType, ObjectInstanceRigidBody, RuntimeGameObjectInstance, RuntimeObjectInstance } from "../types";
|
||||
import type { ObjectType, RuntimeGameObjectInstance, RuntimeObjectInstance } from "../types";
|
||||
import { useEffect, useImperativeHandle, useRef, type Ref } from "react";
|
||||
import { Euler, Quaternion, type Group } from "three";
|
||||
import { Instance, Instances } from "@react-three/drei";
|
||||
@@ -94,9 +94,9 @@ export const ObjectViewInternal = function ({ object, objectType, ref, ...props
|
||||
return;
|
||||
const otherObj = Object.values(game.scene.objects)
|
||||
.find((o) => o.rb()?.handle === otherHandle);
|
||||
game.emitEvent('object_touch_start', { object: gameObj, other: otherObj });
|
||||
game.emitEvent('objectTouchStart', { object: gameObj, other: otherObj });
|
||||
if (otherObj?.id === game.scene.playerObjectId)
|
||||
game.emitEvent('player_touch_start', { object: gameObj, other: otherObj });
|
||||
game.emitEvent('playerTouchStart', { object: gameObj, other: otherObj });
|
||||
}}
|
||||
onSync={(data) => {
|
||||
runInAction(() => {
|
||||
|
||||
@@ -5,70 +5,11 @@ import * as Blockly from "blockly";
|
||||
import type { ObjectType } from "../../types";
|
||||
import './ScriptEditorView.scss';
|
||||
|
||||
import '../../blockly';
|
||||
import { gameTheme, generateCode } from '../../blockly';
|
||||
|
||||
const TOOLBOX: Blockly.utils.toolbox.ToolboxDefinition = {
|
||||
kind: 'categoryToolbox',
|
||||
contents: [
|
||||
{
|
||||
kind: 'category',
|
||||
name: 'Events',
|
||||
colour: '180',
|
||||
contents: [
|
||||
{ kind: 'block', type: 'game_start_event' },
|
||||
{ kind: 'block', type: 'object_touch_start_event' },
|
||||
{ kind: 'block', type: 'player_touch_start_event' },
|
||||
{ kind: 'block', type: 'object_clicked_event' },
|
||||
],
|
||||
},
|
||||
{
|
||||
kind: 'category',
|
||||
name: 'Values',
|
||||
colour: '260',
|
||||
contents: [
|
||||
{ kind: 'block', type: 'current_object_value' },
|
||||
{ kind: 'block', type: 'current_object_type_value' },
|
||||
{ kind: 'block', type: 'object_type_value' },
|
||||
{ kind: 'block', type: 'any_object_of_type_value' },
|
||||
{ kind: 'block', type: 'position_of_object_value' },
|
||||
{ kind: 'block', type: 'pos_value' },
|
||||
{ kind: 'block', type: 'dpos_value' },
|
||||
{ kind: 'block', type: 'direction_to_position_value' },
|
||||
{ kind: 'block', type: 'object_by_id_value' },
|
||||
{ kind: 'block', type: 'player_object_value' },
|
||||
],
|
||||
},
|
||||
{
|
||||
kind: 'category',
|
||||
name: 'Loops',
|
||||
colour: '50',
|
||||
contents: [
|
||||
{ kind: 'block', type: 'loop_forever' },
|
||||
],
|
||||
},
|
||||
{
|
||||
kind: 'category',
|
||||
name: 'Actions',
|
||||
colour: '20',
|
||||
contents: [
|
||||
{ kind: 'block', type: 'console_log_action' },
|
||||
{ kind: 'block', type: 'move_to_position_action' },
|
||||
{ kind: 'block', type: 'move_in_direction_action' },
|
||||
{ kind: 'block', type: 'physics_apply_impulse_action' },
|
||||
{ kind: 'block', type: 'wait_seconds_action' },
|
||||
],
|
||||
},
|
||||
{
|
||||
kind: 'category',
|
||||
name: 'Text',
|
||||
colour: '160',
|
||||
contents: [
|
||||
{ kind: 'block', type: 'text' },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
import '../../blockly/registrar';
|
||||
import * as blocklyBarrel from '../../blockly';
|
||||
import { gameTheme } from '../../blockly';
|
||||
import { recompileAll } from '../../blockly/recompile';
|
||||
import { state } from '../../state';
|
||||
|
||||
type ScriptEditorViewProps = {
|
||||
objectType: ObjectType;
|
||||
@@ -76,29 +17,44 @@ type ScriptEditorViewProps = {
|
||||
|
||||
export const ScriptEditorView = observer(function ({ objectType }: ScriptEditorViewProps) {
|
||||
const [popup, setPopup] = useState<{ title: string; content: string } | null>(null);
|
||||
const [blocklyKey, setBlocklyKey] = useState(0);
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const workspaceRef = useRef<Blockly.WorkspaceSvg | null>(null);
|
||||
const objectTypeRef = useRef(objectType);
|
||||
useLayoutEffect(() => { objectTypeRef.current = objectType; });
|
||||
|
||||
useEffect(() => {
|
||||
if (!import.meta.hot)
|
||||
return;
|
||||
const handler = () => {
|
||||
recompileAll(state.world.data.objectTypes);
|
||||
setBlocklyKey(k => k + 1);
|
||||
};
|
||||
window.addEventListener('blockly-hmr', handler);
|
||||
return () => window.removeEventListener('blockly-hmr', handler);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!containerRef.current)
|
||||
return;
|
||||
|
||||
const workspace = Blockly.inject(containerRef.current, { toolbox: TOOLBOX, theme: gameTheme });
|
||||
const toolbox = blocklyBarrel.barrelToToolbox(blocklyBarrel as Record<string, unknown>);
|
||||
const workspace = Blockly.inject(containerRef.current, { toolbox, theme: gameTheme });
|
||||
workspaceRef.current = workspace;
|
||||
|
||||
const listener = (e: Blockly.Events.Abstract) => {
|
||||
if (e.isUiEvent)
|
||||
return;
|
||||
|
||||
console.log('change event');
|
||||
|
||||
runInAction(() => {
|
||||
const current = objectTypeRef.current;
|
||||
const serialized = JSON.stringify(Blockly.serialization.workspaces.save(workspace));
|
||||
current.program = serialized;
|
||||
|
||||
try {
|
||||
current.javascript = generateCode(workspace);
|
||||
current.javascript = blocklyBarrel.generateCode(workspace);
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
@@ -128,7 +84,9 @@ export const ScriptEditorView = observer(function ({ objectType }: ScriptEditorV
|
||||
workspace.dispose();
|
||||
workspaceRef.current = null;
|
||||
};
|
||||
}, [objectType.program]);
|
||||
// workspace should not reload when objectType.program changes
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [blocklyKey]);
|
||||
|
||||
useEffect(() => {
|
||||
const workspace = workspaceRef.current;
|
||||
@@ -145,7 +103,7 @@ export const ScriptEditorView = observer(function ({ objectType }: ScriptEditorV
|
||||
} finally {
|
||||
Blockly.Events.enable();
|
||||
}
|
||||
}, [objectType.id, objectType.program]);
|
||||
}, [objectType.id]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
const showProgram = () => {
|
||||
const raw = objectType.program;
|
||||
|
||||
Reference in New Issue
Block a user