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

[Minecraft] dynamically add procedure call blocks to flyout #57609

Merged
merged 1 commit into from Mar 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
43 changes: 43 additions & 0 deletions apps/src/blockly/addons/cdoUtils.ts
Expand Up @@ -31,6 +31,7 @@ import {Block, BlockSvg, Field, Theme, WorkspaceSvg} from 'blockly';
import {BlockColor, JsonBlockConfig, WorkspaceSerialization} from '../types';
import experiments from '@cdo/apps/util/experiments';
import {getBaseName} from '../utils';
import {ToolboxItemInfo} from 'blockly/core/utils/toolbox';

/**
* Loads blocks to a workspace.
Expand Down Expand Up @@ -58,6 +59,48 @@ export function loadBlocksToWorkspace(
Blockly.serialization.workspaces.load(mainSource, workspace);
positionBlocksOnWorkspace(workspace);
Blockly.hasLoadedBlocks = true;

// Dynamically add procedure call blocks to an uncategorized toolbox
// if specified in the level config (e.g. Minecraft Agent levels).
// Levels will include: "top_level_procedure_autopopulate": "true"
if (Blockly.topLevelProcedureAutopopulate) {
addProcedureCallBlocksToFlyout(workspace, mainSource);
}
}

function addProcedureCallBlocksToFlyout(
workspace: WorkspaceSvg,
mainSource: WorkspaceSerialization
) {
// options.languageTree is the translated toolbox info
if (workspace.getFlyout() && workspace.options?.languageTree) {
const callBlocks = [] as ToolboxItemInfo[];
const defBlocks = mainSource.blocks.blocks.filter(
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit, non-blocking: Prefer just to write out definition blocks here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed. If there are no other changes requested, I may save this for an immediate follow-up so we don't have to rerun drone.

Copy link
Contributor

Choose a reason for hiding this comment

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

Agreed!

block => block.type === 'procedures_defnoreturn'
);
defBlocks.forEach(def => {
// Procedure definitions should have a valid name
if (typeof def.fields?.NAME === 'string') {
// Create the block XML for a procedure call block.
const block = document.createElement('block');
block.setAttribute('type', 'procedures_callnoreturn');
const mutation = document.createElement('mutation');
mutation.setAttribute('name', def.fields.NAME);
block.appendChild(mutation);

callBlocks.push({
kind: 'BLOCK',
blockxml: block,
type: 'procedures_callnoreturn',
});
}
});
if (callBlocks.length) {
// Add the new callblocks to the toolbox and refresh it.
workspace.options.languageTree.contents.push(...callBlocks);
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this the first place we're using language tree like this? It feels new to me, but I'm surprised to feel like I'm seeing it for the first time.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

See updated description and let me know if you have more questions. It's new to the main repo, but supported in both Blockly versions.

workspace.getFlyout()?.show(workspace.options.languageTree);
}
}
}

/**
Expand Down
3 changes: 3 additions & 0 deletions apps/src/blockly/googleBlocklyWrapper.ts
Expand Up @@ -729,6 +729,9 @@ function initializeBlocklyWrapper(blocklyInstance: GoogleBlocklyInstance) {
options
) as ExtendedWorkspaceSvg;

blocklyWrapper.topLevelProcedureAutopopulate =
!!options.topLevelProcedureAutopopulate;

if (options.noFunctionBlockFrame) {
workspace.noFunctionBlockFrame = options.noFunctionBlockFrame;
}
Expand Down
2 changes: 2 additions & 0 deletions apps/src/blockly/types.ts
Expand Up @@ -67,6 +67,7 @@ type GoogleBlocklyType = typeof GoogleBlockly;

// Type for the Blockly instance created and modified by googleBlocklyWrapper.
export interface BlocklyWrapperType extends GoogleBlocklyType {
topLevelProcedureAutopopulate: boolean;
getNewCursor: (type: string) => Cursor;
LineCursor: typeof GoogleBlockly.BasicCursor;
version: BlocklyVersion;
Expand Down Expand Up @@ -217,6 +218,7 @@ export interface ExtendedBlocklyOptions extends BlocklyOptions {
levelBlockIds: string[];
isBlockEditMode: boolean;
editBlocks: string | undefined;
topLevelProcedureAutopopulate: boolean | undefined;
noFunctionBlockFrame: boolean;
useModalFunctionEditor: boolean;
useBlocklyDynamicCategories: boolean;
Expand Down