diff --git a/src/commands/gxgames/api/index.ts b/src/commands/gxgames/api/index.ts index 8616281..bfd8846 100644 --- a/src/commands/gxgames/api/index.ts +++ b/src/commands/gxgames/api/index.ts @@ -20,6 +20,15 @@ import { GG_API } from "../config"; export { LinkStorage, type GxGamesLink } from "./storage"; +export const apiUserErrorMessage = ( + errors: readonly { description: string }[], +): string => + errors + .map( + (e) => e.description.slice(0, 1).toUpperCase() + e.description.slice(1), + ) + .join(".\n"); + export function getApiClient( ctx: Context, auth: { diff --git a/src/commands/gxgames/commands/link-impl.ts b/src/commands/gxgames/commands/link-impl.ts index 4308241..cbd4ec9 100644 --- a/src/commands/gxgames/commands/link-impl.ts +++ b/src/commands/gxgames/commands/link-impl.ts @@ -20,7 +20,7 @@ import { KnownError } from "~/error"; import type { ProjectPath } from "~/project"; import { createAuthManager } from "../auth"; -import { getApiClient } from "../api"; +import { apiUserErrorMessage, getApiClient } from "../api"; import { LinkStorage } from "../api"; export default async function ( @@ -38,7 +38,7 @@ export default async function ( if (!studioId) { const studiosRes = await api.getUserStudios({ pageSize: 999 }); if (!studiosRes.success) { - throw new KnownError(studiosRes.errors); + throw new KnownError(apiUserErrorMessage(studiosRes.errors)); } const selected = await p.select({ @@ -61,7 +61,7 @@ export default async function ( gameEngine: ["game-maker"], }); if (!gamesRes.success) { - throw new KnownError(gamesRes.errors); + throw new KnownError(apiUserErrorMessage(gamesRes.errors)); } const selected = await p.select({ @@ -90,7 +90,7 @@ export default async function ( gameEngine: "game-maker", }); if (!res.success) { - throw new KnownError(res.errors); + throw new KnownError(apiUserErrorMessage(res.errors)); } gameId = res.data.gameId; createLog.success(`Game created: ${gameId}`); diff --git a/src/commands/gxgames/commands/meta-impl.ts b/src/commands/gxgames/commands/meta-impl.ts index 2801d97..f769eae 100644 --- a/src/commands/gxgames/commands/meta-impl.ts +++ b/src/commands/gxgames/commands/meta-impl.ts @@ -18,7 +18,7 @@ import type { Context } from "~/context"; import { KnownError } from "~/error"; import type { ProjectPath } from "~/project"; -import { LinkStorage } from "../api"; +import { apiUserErrorMessage, LinkStorage } from "../api"; import { createAuthManager } from "../auth"; import { getApiClient } from "../api"; import type { @@ -47,7 +47,7 @@ export default async function ( const gameRes = await api.getGameDetails(link.gameId); if (!gameRes.success) { - throw new KnownError(gameRes.errors); + throw new KnownError(apiUserErrorMessage(gameRes.errors)); } const game = gameRes.data; @@ -79,7 +79,7 @@ export default async function ( updateLog.success("Metadata unchanged"); } else { updateLog.error("Failed"); - throw new KnownError(updateRes.errors); + throw new KnownError(apiUserErrorMessage(updateRes.errors)); } } else { updateLog.success("Metadata updated"); @@ -97,7 +97,7 @@ export default async function ( ); if (!coverRes.success) { coverLog.error("Failed"); - throw new KnownError(coverRes.errors); + throw new KnownError(apiUserErrorMessage(coverRes.errors)); } coverLog.success("Cover uploaded"); } @@ -112,7 +112,7 @@ export default async function ( }); if (!graphicRes.success) { graphicLog.error("Failed"); - throw new KnownError(graphicRes.errors); + throw new KnownError(apiUserErrorMessage(graphicRes.errors)); } graphicLog.success("Graphic uploaded"); } diff --git a/src/commands/gxgames/commands/publish-impl.ts b/src/commands/gxgames/commands/publish-impl.ts index 32c0a5f..3f4b47b 100644 --- a/src/commands/gxgames/commands/publish-impl.ts +++ b/src/commands/gxgames/commands/publish-impl.ts @@ -19,7 +19,7 @@ import chalk from "chalk"; import { KnownError } from "~/error"; import type { ProjectPath } from "~/project"; -import { LinkStorage } from "../api"; +import { apiUserErrorMessage, LinkStorage } from "../api"; import { createAuthManager } from "../auth"; import { getApiClient } from "../api"; @@ -44,7 +44,7 @@ export default async function ( ), ); } - throw new KnownError(res.errors); + throw new KnownError(apiUserErrorMessage(res.errors)); } publishLog.success("Game published!"); diff --git a/src/commands/gxgames/commands/upload-impl.ts b/src/commands/gxgames/commands/upload-impl.ts index 4d4c339..f076959 100644 --- a/src/commands/gxgames/commands/upload-impl.ts +++ b/src/commands/gxgames/commands/upload-impl.ts @@ -17,7 +17,7 @@ import type { Context } from "~/context"; import * as p from "@clack/prompts"; import chalk from "chalk"; -import { getApiClient } from "../api"; +import { apiUserErrorMessage, getApiClient } from "../api"; import { createAuthManager } from "../auth"; import { KnownError } from "~/error"; import type { ProjectPath } from "~/project"; @@ -40,7 +40,7 @@ export default async function ( gameEngine: ["game-maker"], }); if (!gamesRes.success) { - throw new KnownError(gamesRes.errors); + throw new KnownError(apiUserErrorMessage(gamesRes.errors)); } const previousVersion = gamesRes.data.games.find( @@ -70,7 +70,7 @@ export default async function ( { file: new File([fileBuffer], this.path.basename(flags.file)) }, ); if (!res.success) { - throw new KnownError(res.errors); + throw new KnownError(apiUserErrorMessage(res.errors)); } uploadLog.success("Bundle uploaded"); diff --git a/src/error.ts b/src/error.ts index e5cb3a3..bb3a068 100644 --- a/src/error.ts +++ b/src/error.ts @@ -20,10 +20,7 @@ */ export class KnownError extends Error { constructor(cause: unknown) { - const message = - cause instanceof Error - ? cause.message - : JSON.stringify(cause, undefined, 2); + const message = cause instanceof Error ? cause.message : String(cause); super(message, cause instanceof Error ? { cause } : undefined); this.name = "KnownError"; } diff --git a/test-game/.gitattributes b/test-game/.gitattributes new file mode 100644 index 0000000..1fa0145 --- /dev/null +++ b/test-game/.gitattributes @@ -0,0 +1,9 @@ + +# Ignore .yy files for language statistics +*.yy linguist-generated=true + +# force LF for metadata files for merge simplicity +*.gml text eol=lf +*.yy text eol=lf +*.yyp text eol=lf +*.json text eol=lf diff --git a/test-game/.github/workflows/compile.yml b/test-game/.github/workflows/compile.yml new file mode 100644 index 0000000..1b8fed1 --- /dev/null +++ b/test-game/.github/workflows/compile.yml @@ -0,0 +1,52 @@ +name: Compile + +# This job triggers when opening/updating a pull request or merging to the main branch +on: + pull_request: + types: [opened, synchronize, reopened] + push: + branches: [main] + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +env: + # You can pin a particular version by replacing latest. E.g., @gamemaker/gm-cli@1.0.2 + GM_COMMAND: "@gamemaker/gm-cli@latest" + +jobs: + compile: + runs-on: ubuntu-latest + + steps: + # Check out the git branch to build against + - name: Checkout + uses: actions/checkout@v6 + + # Save a cache that can be reused between runs. + # This will future runs faster, just like when you build the game locally + - name: Cache + uses: actions/cache@v5 + with: + path: .gmcache + key: ${{ runner.os }}-gmcache + + # ffmpeg is needed for linux: https://github.com/YoYoGames/GameMaker-Bugs/issues/4977 + - name: Set up ffmpeg + if: ${{ runner.os == 'Linux' }} + uses: FedericoCarboni/setup-ffmpeg@v3 + with: + ffmpeg-version: "6.1.0" + + # You can create an access token at https://gamemaker.io/en/account/access-keys + # Then, in github, set a Repository Secret named GAMEMAKER_PAT with that value + # in you repository Settings/Secrets and Varibles/Actions/New repository secret + - run: npx "$GM_COMMAND" login "$GAMEMAKER_PAT" + if: ${{ env.GAMEMAKER_PAT != '' }} + + # "Test compile" the game. Does not produce a bundle, but rather checks that it + # possible to compile the game + - run: npx "$GM_COMMAND" compile + env: + NO_COLOR: 1 diff --git a/test-game/.github/workflows/package.yml b/test-game/.github/workflows/package.yml new file mode 100644 index 0000000..69ebbb7 --- /dev/null +++ b/test-game/.github/workflows/package.yml @@ -0,0 +1,67 @@ +name: Package +# This jobs start when the user trigger it manually from Github repository/Actions +on: [workflow_dispatch] + +env: + GAME_NAME: "test-game" + # You can pin a particular version by replacing latest. E.g., @gamemaker/gm-cli@1.0.2 + GM_COMMAND: "@gamemaker/gm-cli@latest" + +jobs: + compile: + strategy: + matrix: + # Select any runner and targets you want to build with + # runner: The machine that builds your game. See https://docs.github.com/en/actions/how-tos/write-workflows/choose-where-workflows-run/choose-the-runner-for-a-job + # target: The platform the game will run on. + include: + - runner: ubuntu-latest + target: operagx + # - runner: ubuntu-latest + # target: linux + # - runner: ubuntu-latest + # target: windows + # - runner: macos-latest + # target: mac + runs-on: ${{ matrix.runner }} + + steps: + # Check out the git branch to build against + - name: Checkout + uses: actions/checkout@v6 + + # Save a cache that can be reused between runs. + # This will future runs faster, just like when you build the game locally + - name: Cache + uses: actions/cache@v5 + with: + path: .gmcache + key: ${{ runner.os }}-gmcache-${{ matrix.target }} + + # ffmpeg is needed for linux: https://github.com/YoYoGames/GameMaker-Bugs/issues/4977 + - name: Set up ffmpeg + if: ${{ runner.os == 'Linux' }} + uses: FedericoCarboni/setup-ffmpeg@v3 + with: + ffmpeg-version: "6.1.0" + + # You can create an access token at https://gamemaker.io/en/account/access-keys + # Then, in github, set a Repository Secret named GAMEMAKER_PAT with that value + # in you repository Settings/Secrets and Varibles/Actions/New repository secret + - run: npx "$GM_COMMAND" login "$GAMEMAKER_PAT" + if: ${{ env.GAMEMAKER_PAT != '' }} + + # Build and package the game. Create a file called package.zip. + - run: npx "$GM_COMMAND" package --target ${{ matrix.target }} --output ./package.zip + env: + NO_COLOR: 1 + + # Create the final name on the format `name-target-commit.zip` For example `spacerocks-windows-5e0179f.zip` + - name: Create artifact name + run: echo "ARTIFACT_NAME=${GAME_NAME}-${{ matrix.target }}-${GITHUB_SHA::7}.zip" >> $GITHUB_ENV + + # Upload the game. You can then find it in you github repo under Actions//Artifacts + - uses: actions/upload-artifact@v7 + with: + name: ${{ env.ARTIFACT_NAME }} + path: ./package.zip diff --git a/test-game/.gitignore b/test-game/.gitignore new file mode 100644 index 0000000..7abb693 --- /dev/null +++ b/test-game/.gitignore @@ -0,0 +1,63 @@ + +# Windows + +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# Mac + +## General +.DS_Store +.AppleDouble +.LSOverride + +## Icon must end with two +Icon + +## Thumbnails +._* + +## Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +## Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# GameMaker temporary files +*.resource_order +*.old + +# GMRT build directory +Build diff --git a/test-game/.mcp.json b/test-game/.mcp.json new file mode 100644 index 0000000..faa8e1e --- /dev/null +++ b/test-game/.mcp.json @@ -0,0 +1,10 @@ +{ + "mcpServers": { + "gamemaker-resource-tool": { + "type": "stdio", + "command": "npx", + "args": ["@gamemaker/gm-cli@latest", "resourcetool", "mcp"], + "env": {} + } + } +} diff --git a/test-game/AGENTS.md b/test-game/AGENTS.md new file mode 100644 index 0000000..b372a59 --- /dev/null +++ b/test-game/AGENTS.md @@ -0,0 +1,78 @@ +# Editing GameMaker project files + +Do not make changes to `.yy` or `.yyp` files yourself. +It's very hard to correctly edit these manually! +You MUST use commands exposed by the `gamemaker-resource-tool` MCP server. + +# GameMaker Language (GML) Guidance + +Make changes to `.gml` files using your built-in tools, if you so wish. + +## GML Naming conventions + +- Use `snake_case` for all variables and functions +- Prefix local variables with `_` (e.g., `var _temp_value`, `var _effect`) +- Prefix resource names based on their type, e.g. obj_player, spr_player, etc. + +## GML reserved names + +Your own names must avoid clashing with these: + +- `score`, `lives`, `health` +- Position: `x`, `y` +- Sprite: `sprite_index`, `image_index`, `image_speed`, `image_xscale`, `image_yscale`, `image_angle`, `image_alpha`, `image_blend` +- Physics: `speed`, `direction`, `friction`, `gravity`, `gravity_direction` +- Collision: `bbox_left`, `bbox_right`, `bbox_top`, `bbox_bottom` +- Instance: `id`, `object_index`, `layer`, `depth`, `visible`, `persistent` + +## Modern idiomatic GML + +GML has support for **structs** (dynamic objects similar to JavaScript). + +```gml +var _mystruct = +{ + a : 20, + b : "Hello World" +}; + +// There is support for constructor functions and methods tied to the struct too +function Vector2(_x, _y) constructor +{ + x = _x; + y = _y; + + static Add = function(_vec2) + { + x += _vec2.x; + y += _vec2.y; + } +} + +v2 = new Vector2(10, 10); +``` + +GML _script_ files now requires one or more function definitions + +```gml +// in move script +function move(spd, dir) +{ + speed = spd; + direction = dir; +} + +``` + +## Library Functions + +- Prefer `instance_create_layer()` over deprecated `instance_create()` + +# Running / debugging games + +To help users debug and play games you can make use of: + +``` +npx @gamemaker/gm-cli compile --errors-only +npx @gamemaker/gm-cli run --errors-only +``` diff --git a/test-game/CLAUDE.md b/test-game/CLAUDE.md new file mode 100644 index 0000000..b372a59 --- /dev/null +++ b/test-game/CLAUDE.md @@ -0,0 +1,78 @@ +# Editing GameMaker project files + +Do not make changes to `.yy` or `.yyp` files yourself. +It's very hard to correctly edit these manually! +You MUST use commands exposed by the `gamemaker-resource-tool` MCP server. + +# GameMaker Language (GML) Guidance + +Make changes to `.gml` files using your built-in tools, if you so wish. + +## GML Naming conventions + +- Use `snake_case` for all variables and functions +- Prefix local variables with `_` (e.g., `var _temp_value`, `var _effect`) +- Prefix resource names based on their type, e.g. obj_player, spr_player, etc. + +## GML reserved names + +Your own names must avoid clashing with these: + +- `score`, `lives`, `health` +- Position: `x`, `y` +- Sprite: `sprite_index`, `image_index`, `image_speed`, `image_xscale`, `image_yscale`, `image_angle`, `image_alpha`, `image_blend` +- Physics: `speed`, `direction`, `friction`, `gravity`, `gravity_direction` +- Collision: `bbox_left`, `bbox_right`, `bbox_top`, `bbox_bottom` +- Instance: `id`, `object_index`, `layer`, `depth`, `visible`, `persistent` + +## Modern idiomatic GML + +GML has support for **structs** (dynamic objects similar to JavaScript). + +```gml +var _mystruct = +{ + a : 20, + b : "Hello World" +}; + +// There is support for constructor functions and methods tied to the struct too +function Vector2(_x, _y) constructor +{ + x = _x; + y = _y; + + static Add = function(_vec2) + { + x += _vec2.x; + y += _vec2.y; + } +} + +v2 = new Vector2(10, 10); +``` + +GML _script_ files now requires one or more function definitions + +```gml +// in move script +function move(spd, dir) +{ + speed = spd; + direction = dir; +} + +``` + +## Library Functions + +- Prefer `instance_create_layer()` over deprecated `instance_create()` + +# Running / debugging games + +To help users debug and play games you can make use of: + +``` +npx @gamemaker/gm-cli compile --errors-only +npx @gamemaker/gm-cli run --errors-only +``` diff --git a/test-game/options/linux/options_linux.yy b/test-game/options/linux/options_linux.yy new file mode 100644 index 0000000..704fafc --- /dev/null +++ b/test-game/options/linux/options_linux.yy @@ -0,0 +1,26 @@ +{ + "$GMLinuxOptions": "", + "%Name": "Linux", + "name": "Linux", + "option_linux_allow_fullscreen": false, + "option_linux_disable_sandbox": false, + "option_linux_display_cursor": true, + "option_linux_display_name": "test-game", + "option_linux_display_splash": false, + "option_linux_enable_steam": false, + "option_linux_homepage": "http://www.yoyogames.com", + "option_linux_icon": "${base_options_dir}/linux/icons/64.png", + "option_linux_interpolate_pixels": true, + "option_linux_long_desc": "", + "option_linux_maintainer_email": "", + "option_linux_resize_window": false, + "option_linux_scale": 0, + "option_linux_short_desc": "", + "option_linux_splash_screen": "${base_options_dir}/linux/splash/splash.png", + "option_linux_start_fullscreen": false, + "option_linux_sync": true, + "option_linux_texture_page": "2048x2048", + "option_linux_version": "1.0.0.0", + "resourceType": "GMLinuxOptions", + "resourceVersion": "2.0" +} diff --git a/test-game/options/mac/options_mac.yy b/test-game/options/mac/options_mac.yy new file mode 100644 index 0000000..758c5bc --- /dev/null +++ b/test-game/options/mac/options_mac.yy @@ -0,0 +1,38 @@ +{ + "$GMMacOptions": "", + "%Name": "macOS", + "name": "macOS", + "option_mac_allow_fullscreen": false, + "option_mac_allow_incoming_network": false, + "option_mac_allow_outgoing_network": false, + "option_mac_apple_sign_in": false, + "option_mac_app_category": "Games", + "option_mac_app_id": "com.company.game", + "option_mac_arm64": true, + "option_mac_build_app_store": false, + "option_mac_build_number": 0, + "option_mac_copyright": "", + "option_mac_disable_sandbox": false, + "option_mac_display_cursor": true, + "option_mac_display_name": "test-game", + "option_mac_enable_retina": false, + "option_mac_enable_steam": false, + "option_mac_icon_png": "${base_options_dir}/mac/icons/1024.png", + "option_mac_installer_background_png": "${base_options_dir}/mac/splash/installer_background.png", + "option_mac_interpolate_pixels": true, + "option_mac_menu_dock": false, + "option_mac_min_version": "10.10", + "option_mac_output_dir": "~/gamemakerstudio2", + "option_mac_resize_window": false, + "option_mac_scale": 0, + "option_mac_signing_identity": "Developer ID Application:", + "option_mac_splash_png": "${base_options_dir}/mac/splash/splash.png", + "option_mac_start_fullscreen": false, + "option_mac_team_id": "", + "option_mac_texture_page": "2048x2048", + "option_mac_version": "1.0.0.0", + "option_mac_vsync": true, + "option_mac_x86_64": true, + "resourceType": "GMMacOptions", + "resourceVersion": "2.0" +} diff --git a/test-game/options/main/options_main.yy b/test-game/options/main/options_main.yy new file mode 100644 index 0000000..1431894 --- /dev/null +++ b/test-game/options/main/options_main.yy @@ -0,0 +1,29 @@ +{ + "$GMMainOptions": "v5", + "%Name": "Main", + "name": "Main", + "option_allow_instance_change": false, + "option_audio_error_behaviour": false, + "option_author": "", + "option_collision_compatibility": false, + "option_copy_on_write_enabled": false, + "option_draw_colour": 4294967295, + "option_gameguid": "697ab10f-91f0-499e-83c3-b7855e1aa10d", + "option_gameid": "0", + "option_game_speed": 60, + "option_legacy_json_parsing": false, + "option_legacy_number_conversion": false, + "option_legacy_other_behaviour": false, + "option_legacy_primitive_drawing": false, + "option_mips_for_3d_textures": false, + "option_remove_unused_assets": true, + "option_sci_usesci": false, + "option_spine_licence": false, + "option_steam_app_id": "0", + "option_template_description": null, + "option_template_icon": "${base_options_dir}/main/template_icon.png", + "option_template_image": "${base_options_dir}/main/template_image.png", + "option_window_colour": 255, + "resourceType": "GMMainOptions", + "resourceVersion": "2.0" +} diff --git a/test-game/options/windows/options_windows.yy b/test-game/options/windows/options_windows.yy new file mode 100644 index 0000000..89b5d48 --- /dev/null +++ b/test-game/options/windows/options_windows.yy @@ -0,0 +1,38 @@ +{ + "$GMWindowsOptions": "v2", + "%Name": "Windows", + "name": "Windows", + "option_windows_allow_fullscreen_switching": false, + "option_windows_borderless": false, + "option_windows_company_info": "YoYo Games Ltd", + "option_windows_copyright_info": "", + "option_windows_copy_exe_to_dest": false, + "option_windows_d3dswapeffectdiscard": false, + "option_windows_description_info": "A GameMaker Game", + "option_windows_disable_sandbox": false, + "option_windows_display_cursor": true, + "option_windows_display_name": "test-game", + "option_windows_enable_steam": false, + "option_windows_executable_name": "test-game.exe", + "option_windows_icon": "${base_options_dir}/windows/icons/icon.ico", + "option_windows_installer_finished": "${base_options_dir}/windows/installer/finished.bmp", + "option_windows_installer_header": "${base_options_dir}/windows/installer/header.bmp", + "option_windows_interpolate_pixels": true, + "option_windows_license": "${base_options_dir}/windows/installer/license.txt", + "option_windows_nsis_file": "${base_options_dir}/windows/installer/nsis_script.nsi", + "option_windows_product_info": "test-game", + "option_windows_resize_window": false, + "option_windows_save_location": 0, + "option_windows_scale": 0, + "option_windows_sleep_margin": 10, + "option_windows_splash_screen": "${base_options_dir}/windows/splash/splash.png", + "option_windows_start_fullscreen": false, + "option_windows_steam_use_alternative_launcher": false, + "option_windows_texture_page": "2048x2048", + "option_windows_use_raw_mouse": false, + "option_windows_use_splash": false, + "option_windows_version": "1.0.0.0", + "option_windows_vsync": true, + "resourceType": "GMWindowsOptions", + "resourceVersion": "2.0" +} diff --git a/test-game/rooms/room1/room1.yy b/test-game/rooms/room1/room1.yy new file mode 100644 index 0000000..80d57c5 --- /dev/null +++ b/test-game/rooms/room1/room1.yy @@ -0,0 +1,234 @@ +{ + "$GMRoom": "v1", + "%Name": "room1", + "creationCodeFile": "", + "inheritCode": false, + "inheritCreationOrder": false, + "inheritLayers": false, + "instanceCreationOrder": [], + "isDnd": false, + "layers": [ + { + "$GMRInstanceLayer": "", + "%Name": "Instances", + "depth": 0, + "effectEnabled": true, + "effectType": null, + "gridX": 16, + "gridY": 16, + "hierarchyFrozen": false, + "inheritLayerDepth": false, + "inheritLayerSettings": false, + "inheritSubLayers": true, + "inheritVisibility": true, + "instances": [], + "layers": [], + "name": "Instances", + "properties": [], + "resourceType": "GMRInstanceLayer", + "resourceVersion": "2.0", + "userdefinedDepth": false, + "visible": true + }, + { + "$GMRBackgroundLayer": "", + "%Name": "Background", + "animationFPS": 15.0, + "animationSpeedType": 0, + "colour": 4278190080, + "depth": 100, + "effectEnabled": true, + "effectType": null, + "gridX": 32, + "gridY": 32, + "hierarchyFrozen": false, + "hspeed": 0.0, + "htiled": false, + "inheritLayerDepth": false, + "inheritLayerSettings": false, + "inheritSubLayers": true, + "inheritVisibility": true, + "layers": [], + "name": "Background", + "properties": [], + "resourceType": "GMRBackgroundLayer", + "resourceVersion": "2.0", + "spriteId": null, + "stretch": false, + "userdefinedAnimFPS": false, + "userdefinedDepth": false, + "visible": true, + "vspeed": 0.0, + "vtiled": false, + "x": 0, + "y": 0 + } + ], + "name": "room1", + "parent": { + "name": "test-game", + "path": "test-game.yyp" + }, + "parentRoom": null, + "physicsSettings": { + "inheritPhysicsSettings": false, + "PhysicsWorld": false, + "PhysicsWorldGravityX": 0.0, + "PhysicsWorldGravityY": 10.0, + "PhysicsWorldPixToMetres": 0.1 + }, + "resourceType": "GMRoom", + "resourceVersion": "2.0", + "roomSettings": { + "Height": 768, + "inheritRoomSettings": false, + "persistent": false, + "Width": 1366 + }, + "sequenceId": null, + "views": [ + { + "hborder": 32, + "hport": 768, + "hspeed": -1, + "hview": 768, + "inherit": false, + "objectId": null, + "vborder": 32, + "visible": false, + "vspeed": -1, + "wport": 1366, + "wview": 1366, + "xport": 0, + "xview": 0, + "yport": 0, + "yview": 0 + }, + { + "hborder": 32, + "hport": 768, + "hspeed": -1, + "hview": 768, + "inherit": false, + "objectId": null, + "vborder": 32, + "visible": false, + "vspeed": -1, + "wport": 1366, + "wview": 1366, + "xport": 0, + "xview": 0, + "yport": 0, + "yview": 0 + }, + { + "hborder": 32, + "hport": 768, + "hspeed": -1, + "hview": 768, + "inherit": false, + "objectId": null, + "vborder": 32, + "visible": false, + "vspeed": -1, + "wport": 1366, + "wview": 1366, + "xport": 0, + "xview": 0, + "yport": 0, + "yview": 0 + }, + { + "hborder": 32, + "hport": 768, + "hspeed": -1, + "hview": 768, + "inherit": false, + "objectId": null, + "vborder": 32, + "visible": false, + "vspeed": -1, + "wport": 1366, + "wview": 1366, + "xport": 0, + "xview": 0, + "yport": 0, + "yview": 0 + }, + { + "hborder": 32, + "hport": 768, + "hspeed": -1, + "hview": 768, + "inherit": false, + "objectId": null, + "vborder": 32, + "visible": false, + "vspeed": -1, + "wport": 1366, + "wview": 1366, + "xport": 0, + "xview": 0, + "yport": 0, + "yview": 0 + }, + { + "hborder": 32, + "hport": 768, + "hspeed": -1, + "hview": 768, + "inherit": false, + "objectId": null, + "vborder": 32, + "visible": false, + "vspeed": -1, + "wport": 1366, + "wview": 1366, + "xport": 0, + "xview": 0, + "yport": 0, + "yview": 0 + }, + { + "hborder": 32, + "hport": 768, + "hspeed": -1, + "hview": 768, + "inherit": false, + "objectId": null, + "vborder": 32, + "visible": false, + "vspeed": -1, + "wport": 1366, + "wview": 1366, + "xport": 0, + "xview": 0, + "yport": 0, + "yview": 0 + }, + { + "hborder": 32, + "hport": 768, + "hspeed": -1, + "hview": 768, + "inherit": false, + "objectId": null, + "vborder": 32, + "visible": false, + "vspeed": -1, + "wport": 1366, + "wview": 1366, + "xport": 0, + "xview": 0, + "yport": 0, + "yview": 0 + } + ], + "viewSettings": { + "clearDisplayBuffer": true, + "clearViewBackground": false, + "enableViews": false, + "inheritViewSettings": false + }, + "volume": 1.0 +} diff --git a/test-game/test-game.yyp b/test-game/test-game.yyp new file mode 100644 index 0000000..d67d4a0 --- /dev/null +++ b/test-game/test-game.yyp @@ -0,0 +1,53 @@ +{ + "$GMProject": "v1", + "%Name": "test-game", + "AudioGroups": [ + { + "$GMAudioGroup": "v1", + "%Name": "audiogroup_default", + "exportDir": "", + "name": "audiogroup_default", + "resourceType": "GMAudioGroup", + "resourceVersion": "2.0", + "targets": -1 + } + ], + "configs": { + "children": [], + "name": "Default" + }, + "defaultScriptType": 1, + "Folders": [], + "ForcedPrefabProjectReferences": [], + "IncludedFiles": [], + "isEcma": false, + "LibraryEmitters": [], + "MetaData": {}, + "name": "test-game", + "resources": [{ "id": { "name": "room1", "path": "rooms/room1/room1.yy" } }], + "resourceType": "GMProject", + "resourceVersion": "2.0", + "RoomOrderNodes": [ + { "roomId": { "name": "room1", "path": "rooms/room1/room1.yy" } } + ], + "templateType": null, + "TextureGroups": [ + { + "$GMTextureGroup": "", + "%Name": "Default", + "autocrop": true, + "border": 2, + "compressFormat": "bz2", + "customOptions": "", + "directory": "", + "groupParent": null, + "isScaled": true, + "loadType": "default", + "mipsToGenerate": 0, + "name": "Default", + "resourceType": "GMTextureGroup", + "resourceVersion": "2.0", + "targets": -1 + } + ] +} diff --git a/test-game/test-game.zip b/test-game/test-game.zip new file mode 100644 index 0000000..8102357 Binary files /dev/null and b/test-game/test-game.zip differ