diff --git a/schemas/example-plugin-blueprint.json b/schemas/example-plugin-blueprint.json index d3e084d2..6b46f328 100644 --- a/schemas/example-plugin-blueprint.json +++ b/schemas/example-plugin-blueprint.json @@ -1,6 +1,6 @@ { "$schema": "./plugin-blueprint.schema.json", - "format_version": 1, + "format_version": 2, "settings": { "id": "animated_java:blueprint" }, @@ -39,7 +39,7 @@ "rotation": [5, 180, 0], "head_rotation": [5, 180] }, - "display_properties": { + "entity_properties": { "billboard": "vertical", "custom_brightness": 10, "custom_name": "'Bone Node'", @@ -198,7 +198,7 @@ }, "position": [0, 1.625, 0] }, - "display_properties": { + "entity_properties": { "billboard": "vertical", "is_glowing": true, "shadow_radius": 3.0, @@ -224,7 +224,7 @@ "head_rotation": [4.61854, 202.57734], "scale": [1.0625, 1.125, 1] }, - "display_properties": { + "entity_properties": { "billboard": "horizontal", "custom_brightness": 15, "custom_name": "'Block Display Node'", @@ -235,7 +235,7 @@ }, "text_display_node": { "type": "text_display", - "display_properties": { + "entity_properties": { "custom_brightness": 5, "is_custom_brightness_enabled": true, "is_glowing": true, diff --git a/schemas/plugin-blueprint.schema.json b/schemas/plugin-blueprint.schema.json index 33804ef9..9397e8ba 100644 --- a/schemas/plugin-blueprint.schema.json +++ b/schemas/plugin-blueprint.schema.json @@ -164,6 +164,10 @@ "type": { "type": "string" }, + "parent": { + "type": "string", + "pattern": "^[a-z0-9_]+$" + }, "default_transformation": { "$ref": "#/definitions/node_transformation" } @@ -179,7 +183,7 @@ "type": "object", "required": ["elements"], "properties": { - "display_properties": { + "entity_properties": { "$ref": "#/definitions/bone_display_properties" }, "elements": { @@ -200,7 +204,7 @@ "then": { "type": "object", "properties": { - "display_properties": { + "entity_properties": { "$ref": "#/definitions/item_display_properties" } } @@ -215,7 +219,7 @@ "then": { "type": "object", "properties": { - "display_properties": { + "entity_properties": { "$ref": "#/definitions/block_display_properties" } } @@ -230,12 +234,27 @@ "then": { "type": "object", "properties": { - "display_properties": { + "entity_properties": { "$ref": "#/definitions/text_display_properties" } } } }, + { + "if": { + "properties": { + "type": { "const": "interaction" } + } + }, + "then": { + "type": "object", + "properties": { + "entity_properties": { + "$ref": "#/definitions/interaction_entity_properties" + } + } + } + }, { "if": { "properties": { @@ -605,6 +624,20 @@ } ] }, + "interaction_entity_properties": { + "type": "object", + "default": {}, + "properties": { + "width": { + "type": "number", + "default": 1 + }, + "height": { + "type": "number", + "default": 1 + } + } + }, "dynamic_animation": { "type": "object", "required": ["loop_mode", "length"], diff --git a/src/formats/blueprint/settings.ts b/src/formats/blueprint/settings.ts index 4cdd5f52..70e3def9 100644 --- a/src/formats/blueprint/settings.ts +++ b/src/formats/blueprint/settings.ts @@ -327,15 +327,18 @@ export async function validateThisProjectsBlueprintSettings(): Promise< Project.animated_java.render_box[1] ), resource_pack_folder: - Project.animated_java.resource_pack_export_mode === 'folder' + Project.animated_java.resource_pack_export_mode === 'folder' && + !Project.animated_java.enable_plugin_mode ? validateResourcePackFolder(Project.animated_java.resource_pack) : undefined, data_pack_folder: - Project.animated_java.data_pack_export_mode === 'folder' + Project.animated_java.data_pack_export_mode === 'folder' && + !Project.animated_java.enable_plugin_mode ? validateDataPackFolder(Project.animated_java.data_pack) : undefined, data_pack_zip: - Project.animated_java.data_pack_export_mode === 'zip' + Project.animated_java.data_pack_export_mode === 'zip' && + !Project.animated_java.enable_plugin_mode ? validateZipPath(Project.animated_java.data_pack) : undefined, } diff --git a/src/systems/exporter.ts b/src/systems/exporter.ts index 57bc39fb..6422e582 100644 --- a/src/systems/exporter.ts +++ b/src/systems/exporter.ts @@ -131,16 +131,16 @@ async function actuallyExportProject({ const rigHash = hashRig(rig) const animationHash = hashAnimations(animations) - // TODO - Plugin mode should run without the resource pack compiler - // Always run the resource pack compiler because it calculates custom model data. - await resourcepackCompiler(aj.target_minecraft_version, { - rig, - displayItemPath, - resourcePackFolder, - textureExportFolder, - modelExportFolder, - debugMode, - }) + if (!aj.enable_plugin_mode) { + await resourcepackCompiler(aj.target_minecraft_version, { + rig, + displayItemPath, + resourcePackFolder, + textureExportFolder, + modelExportFolder, + debugMode, + }) + } if (!aj.enable_plugin_mode && aj.data_pack_export_mode !== 'none') { await compileDataPack(aj.target_minecraft_version, { diff --git a/src/systems/pluginCompiler.ts b/src/systems/pluginCompiler.ts index f286d2b9..ba95116a 100644 --- a/src/systems/pluginCompiler.ts +++ b/src/systems/pluginCompiler.ts @@ -113,6 +113,7 @@ type NodeType = | 'item_display' | 'block_display' | 'text_display' + | 'interaction' | 'structure' | 'camera' | 'locator' @@ -120,14 +121,16 @@ type NodeType = type PluginNode = | { type: 'bone' + parent?: string default_transformation?: NodeTransformation - display_properties?: Record + entity_properties?: Record elements: BoneElement[] } | { type: Exclude + parent?: string default_transformation?: NodeTransformation - display_properties?: Record + entity_properties?: Record } type LoopMode = { type: 'once' } | { type: 'hold' } | { type: 'loop'; loop_delay?: string } @@ -213,32 +216,6 @@ function parseDataUrl(dataUrl: string): { mimeType: string; base64: string } { return { mimeType, base64 } } -function readTextureAnimation(texture: Texture): TextureAnimation | undefined { - if (!texture.path) return undefined - const mcmetaPath = texture.path + '.mcmeta' - - const { existsSync, readFileSync } = getFsModule() - - if (!existsSync(mcmetaPath)) return undefined - try { - const parsed = JSON.parse(readFileSync(mcmetaPath, 'utf-8')) as { - animation?: Record - } - const anim = parsed.animation as any - if (!anim) return undefined - return scrubUndefined({ - interpolate: anim.interpolate, - width: anim.width, - height: anim.height, - frametime: anim.frametime, - frames: anim.frames, - } satisfies TextureAnimation) - } catch (e) { - console.warn(`Failed to parse texture animation mcmeta for ${texture.name}:`, e) - return undefined - } -} - function serializeNodeTransformation(transform: INodeTransform): NodeTransformation { return scrubUndefined({ matrix: transform.matrix.elements.slice(), @@ -365,12 +342,14 @@ function serializeBoneElements( function serializeNode( node: AnyRenderedNode, options: { + parent?: string defaultVariantModels: Record textureIdToKey: Map textureKeyToPaletteId: Map } ): PluginNode { const base = { + parent: options.parent, default_transformation: serializeNodeTransformation(node.default_transform), } as const @@ -386,7 +365,7 @@ function serializeNode( return scrubUndefined({ type: 'bone', ...base, - display_properties: displayProps, + entity_properties: displayProps, elements: serializeBoneElements(model, { textureIdToKey: options.textureIdToKey, textureKeyToPaletteId: options.textureKeyToPaletteId, @@ -397,7 +376,7 @@ function serializeNode( return scrubUndefined({ type: 'item_display', ...base, - display_properties: scrubUndefined({ + entity_properties: scrubUndefined({ ...displayProps, item: (node as any).item, item_display: (node as any).item_display, @@ -408,7 +387,7 @@ function serializeNode( return scrubUndefined({ type: 'block_display', ...base, - display_properties: scrubUndefined({ + entity_properties: scrubUndefined({ ...displayProps, block_state: (node as any).block, }), @@ -419,7 +398,7 @@ function serializeNode( return scrubUndefined({ type: 'text_display', ...base, - display_properties: scrubUndefined({ + entity_properties: scrubUndefined({ ...displayProps, alignment: (node as any).align, background_color: argb, @@ -431,6 +410,15 @@ function serializeNode( }), } satisfies PluginNode) } + case 'interaction': + return scrubUndefined({ + type: 'interaction', + ...base, + entity_properties: { + width: node.width, + height: node.height, + }, + }) case 'struct': return { type: 'structure', ...base } case 'camera': @@ -507,7 +495,7 @@ function serializeTexture(texture: Texture): PluginTexture { type: 'custom', base64_string: base64, mime_type: mimeType, - animation: readTextureAnimation(texture), + animation: texture.getMCMetaContent()?.animation, } satisfies PluginTexture) } @@ -710,6 +698,7 @@ export function exportPluginBlueprint(options: { const nodeId = nodeUuidToId.get(uuid) if (!nodeId) continue nodes[nodeId] = serializeNode(node, { + parent: node.parent ? nodeUuidToId.get(node.parent) : undefined, defaultVariantModels, textureIdToKey, textureKeyToPaletteId, @@ -725,9 +714,9 @@ export function exportPluginBlueprint(options: { } const blueprint: PluginBlueprintJson = scrubUndefined({ - format_version: 1, + format_version: 2, settings: { - id: `animated_java:${aj.blueprint_id}`, + id: aj.blueprint_id, }, textures, texture_palettes: palettes, diff --git a/src/systems/resourcepackCompiler/index.ts b/src/systems/resourcepackCompiler/index.ts index 3b69684f..dd139920 100644 --- a/src/systems/resourcepackCompiler/index.ts +++ b/src/systems/resourcepackCompiler/index.ts @@ -135,10 +135,7 @@ export default async function compileResourcePack( const { existsSync, promises } = getFsModule() const { writeFile, mkdir, rm, readdir, unlink } = promises - if (aj.enable_plugin_mode) { - // Do nothing - console.log('Plugin mode enabled. Skipping resource pack export.') - } else if (aj.resource_pack_export_mode === 'folder') { + if (aj.resource_pack_export_mode === 'folder') { // Clean up old files PROGRESS_DESCRIPTION.set('Removing Old Resource Pack Files...') PROGRESS.set(0)