diff --git a/example/web-avatar-client/package.json b/example/web-avatar-client/package.json index be5fc231..a1dda919 100644 --- a/example/web-avatar-client/package.json +++ b/example/web-avatar-client/package.json @@ -11,8 +11,7 @@ "iterate": "tsx ./build.ts --watch", "type-check": "tsc --noEmit", "lint": "eslint \"./{src,test}/**/*.{js,jsx,ts,tsx}\" --max-warnings 0", - "lint-fix": "eslint \"./{src,test}/**/*.{js,jsx,ts,tsx}\" --fix", - "test": "jest" + "lint-fix": "eslint \"./{src,test}/**/*.{js,jsx,ts,tsx}\" --fix" }, "dependencies": { "@mml-io/3d-web-client-core": "^0.11.0", diff --git a/example/web-avatar-client/tsconfig.json b/example/web-avatar-client/tsconfig.json index 37953b29..8d7b1a2d 100644 --- a/example/web-avatar-client/tsconfig.json +++ b/example/web-avatar-client/tsconfig.json @@ -19,8 +19,8 @@ "noEmit": true, "baseUrl": ".", "incremental": true, - "skipLibCheck": true + "skipLibCheck": true, }, - "include": ["src/**/*", "test/**/*", "./build.ts"], - "exclude": ["**/build/*", "types-src"] + "include": ["src/**/*", "./build.ts"], + "exclude": ["**/build/*", "types-src"], } diff --git a/example/web-avatar-client/jest.config.ts b/packages/3d-web-avatar/jest.config.ts similarity index 100% rename from example/web-avatar-client/jest.config.ts rename to packages/3d-web-avatar/jest.config.ts diff --git a/packages/3d-web-avatar/package.json b/packages/3d-web-avatar/package.json index a04d71ed..afd06ca4 100644 --- a/packages/3d-web-avatar/package.json +++ b/packages/3d-web-avatar/package.json @@ -16,7 +16,8 @@ "start": "NODE_ENV=production node build/index.js 2>error.log", "type-check": "tsc --noEmit", "lint": "eslint \"./{src,test}/**/*.{js,jsx,ts,tsx}\" --max-warnings 0", - "lint-fix": "eslint \"./{src,test}/**/*.{js,jsx,ts,tsx}\" --fix" + "lint-fix": "eslint \"./{src,test}/**/*.{js,jsx,ts,tsx}\" --fix", + "test": "jest" }, "dependencies": { "react": "^18.2.0", diff --git a/packages/3d-web-avatar/test/collection.json b/packages/3d-web-avatar/test/collection.json new file mode 100644 index 00000000..240635f7 --- /dev/null +++ b/packages/3d-web-avatar/test/collection.json @@ -0,0 +1,77 @@ +{ + "fullBody": [ + { + "name": "Full Body 1", + "asset": "/assets/avatar/parts/SK_Outfit_Body_Male.glb", + "thumb": "/assets/avatar/thumbs/SK_Outfit_Body_Male.jpg" + } + ], + "head": [ + { + "name": "Dude Head 1", + "asset": "/assets/avatar/parts/SK_Outfit_Hat_02.glb", + "thumb": "/assets/avatar/thumbs/SK_Outfit_Hat_02.jpg" + }, + { + "name": "Dude Head 2", + "asset": "/assets/avatar/parts/SK_Outfit_Hat_01.glb", + "thumb": "/assets/avatar/thumbs/SK_Outfit_Hat_01.jpg" + }, + { + "name": "Dude Head 3", + "asset": "/assets/avatar/parts/SK_Outfit_Hat_03.glb", + "thumb": "/assets/avatar/thumbs/SK_Outfit_Hat_03.jpg" + } + ], + "upperBody": [ + { + "name": "Dude Upper Body 1", + "asset": "/assets/avatar/parts/SK_Outfit_One_Hoody_01.glb", + "thumb": "/assets/avatar/thumbs/SK_Outfit_One_Hoody_01.jpg" + }, + { + "name": "Dude Upper Body 2", + "asset": "/assets/avatar/parts/SK_Outfit_Two_Long_Coat_with_Collared_Shirt_01.glb", + "thumb": "/assets/avatar/thumbs/SK_Outfit_Two_Long_Coat_with_Collared_Shirt_01.jpg" + }, + { + "name": "Dude Upper Body 3", + "asset": "/assets/avatar/parts/SK_Outfit_Three_Flanel_Shirt_01.glb", + "thumb": "/assets/avatar/thumbs/SK_Outfit_Three_Flanel_Shirt_01.jpg" + } + ], + "lowerBody": [ + { + "name": "Dude Lower Body 1", + "asset": "/assets/avatar/parts/SK_Outfit_Two_Tight_Joggers_01.glb", + "thumb": "/assets/avatar/thumbs/SK_Outfit_Two_Tight_Joggers_01.jpg" + }, + { + "name": "Dude Lower Body 2", + "asset": "/assets/avatar/parts/SK_Outfit_Three_Tight_Jeans_with_Chain_01.glb", + "thumb": "/assets/avatar/thumbs/SK_Outfit_Three_Tight_Jeans_with_Chain_01.jpg" + }, + { + "name": "Dude Lower Body 3", + "asset": "/assets/avatar/parts/SK_Outfit_One_Cargo_Shorts_01.glb", + "thumb": "/assets/avatar/thumbs/SK_Outfit_One_Cargo_Shorts_01.jpg" + } + ], + "feet": [ + { + "name": "Dude Feet 1", + "asset": "/assets/avatar/parts/SK_Outfit_One_High_Tops_01.glb", + "thumb": "/assets/avatar/thumbs/SK_Outfit_One_High_Tops_01.jpg" + }, + { + "name": "Dude Feet 2", + "asset": "/assets/avatar/parts/SK_Outfit_Three_Mid_Tops_01.glb", + "thumb": "/assets/avatar/thumbs/SK_Outfit_Three_Mid_Tops_01.jpg" + }, + { + "name": "Dude Feet 3", + "asset": "/assets/avatar/parts/SK_Outfit_Three_Mid_Tops_02.glb", + "thumb": "/assets/avatar/thumbs/SK_Outfit_Three_Mid_Tops_02.jpg" + } + ] +} diff --git a/example/web-avatar-client/test/mmlParsing.test.ts b/packages/3d-web-avatar/test/mmlParsing.test.ts similarity index 79% rename from example/web-avatar-client/test/mmlParsing.test.ts rename to packages/3d-web-avatar/test/mmlParsing.test.ts index f9f44029..40a4b7b0 100644 --- a/example/web-avatar-client/test/mmlParsing.test.ts +++ b/packages/3d-web-avatar/test/mmlParsing.test.ts @@ -5,8 +5,7 @@ import { parseMMLDescription } from "@mml-io/3d-web-avatar/src/helpers/parseMMLDescription"; import { findAssetsInCollection } from "@mml-io/3d-web-avatar-editor-ui/src/findAssetsInCollection"; -import collectionData from "../src/collection.json"; - +import collectionData from "./collection.json"; import { semanticallyInvalidString, threeNestedMCharacters, @@ -20,12 +19,20 @@ import { twoRedundantMCharacterswithThreeMModelsEach, twoRedundantMCharacterswithThreeMModelsEachExpectedData, validMCharacter, + validMCharacterWithSocketAttributes, + validMCharacterWithSocketAttributesExpectedData, validMCharacterWithOneInvalidMModel, validMCharacterWithRedundantMCharacterClosingTag, validMCharacterWithRedundantMCharacterClosingTagExpectedData, validMCharacterWithRedundantMModelClosingTag, validMCharacterWithRedundantMModelClosingTagExpectedData, validMCharacterWithTwoInvalidMModels, + validMCharacterWithSocketAndPosition, + validMCharacterWithSocketAndPositionExpectedData, + validMCharacterWithSocketAndRotationInOneAxis, + validMCharacterWithSocketAndRotationInOneAxisExpectedData, + validMCharacterWithNoSocket, + validMCharacterWithNoSocketExpectedData, } from "./test-data"; import { extractNumberFromErrorMessage } from "./test-utils"; @@ -154,3 +161,28 @@ describe("Check against collection", () => { expect(checkCollection.accumulatedErrors).toHaveLength(2); }); }); + +describe("Check with socketed objects", () => { + test("valid tag with socket attributes", async () => { + const [parsedData, errors] = parseMMLDescription(validMCharacterWithSocketAttributes); + expect(errors).toHaveLength(0); + expect(parsedData).toStrictEqual(validMCharacterWithSocketAttributesExpectedData); + }); + test("valid with only position attributes", async () => { + const [parsedData, errors] = parseMMLDescription(validMCharacterWithSocketAndPosition); + expect(errors).toHaveLength(0); + expect(parsedData).toStrictEqual(validMCharacterWithSocketAndPositionExpectedData); + }); + + test("valid with rotation in only one axis", async () => { + const [parsedData, errors] = parseMMLDescription(validMCharacterWithSocketAndRotationInOneAxis); + expect(errors).toHaveLength(0); + expect(parsedData).toStrictEqual(validMCharacterWithSocketAndRotationInOneAxisExpectedData); + }); + + test("valid with no socket attribute", async () => { + const [parsedData, errors] = parseMMLDescription(validMCharacterWithNoSocket); + expect(errors).toHaveLength(0); + expect(parsedData).toStrictEqual(validMCharacterWithNoSocketExpectedData); + }); +}); diff --git a/example/web-avatar-client/test/test-data.ts b/packages/3d-web-avatar/test/test-data.ts similarity index 70% rename from example/web-avatar-client/test/test-data.ts rename to packages/3d-web-avatar/test/test-data.ts index c3215f9b..379e1fcf 100644 --- a/example/web-avatar-client/test/test-data.ts +++ b/packages/3d-web-avatar/test/test-data.ts @@ -34,14 +34,16 @@ export const threeNestedMCharacters = ` export const threeNestedMCharactersExpectedData = { base: { url: "/assets/avatar/parts/SK_Outfit_Body_Male.glb" }, parts: [ - { url: "/assets/avatar/parts/SK_Outfit_Hat_02.glb" }, + { url: "/assets/avatar/parts/SK_Outfit_Hat_02.glb", socket: undefined }, { url: "/assets/avatar/parts/SK_Outfit_Two_Long_Coat_with_Collared_Shirt_01.glb", + socket: undefined, }, { url: "/assets/avatar/parts/SK_Outfit_Three_Tight_Jeans_with_Chain_01.glb", + socket: undefined, }, - { url: "/assets/avatar/parts/SK_Outfit_One_High_Tops_01.glb" }, + { url: "/assets/avatar/parts/SK_Outfit_One_High_Tops_01.glb", socket: undefined }, ], }; @@ -60,14 +62,16 @@ export const threeRogueMModels = ` export const threeRogueMModelsExpectedData = { base: { url: "/assets/avatar/parts/SK_Outfit_Body_Male.glb" }, parts: [ - { url: "/assets/avatar/parts/SK_Outfit_Hat_02.glb" }, + { url: "/assets/avatar/parts/SK_Outfit_Hat_02.glb", socket: undefined }, { url: "/assets/avatar/parts/SK_Outfit_Two_Long_Coat_with_Collared_Shirt_01.glb", + socket: undefined, }, { url: "/assets/avatar/parts/SK_Outfit_Three_Tight_Jeans_with_Chain_01.glb", + socket: undefined, }, - { url: "/assets/avatar/parts/SK_Outfit_One_High_Tops_01.glb" }, + { url: "/assets/avatar/parts/SK_Outfit_One_High_Tops_01.glb", socket: undefined }, ], }; @@ -93,14 +97,16 @@ export const twoRedundantMCharacterswithThreeMModelsEach = ` export const twoRedundantMCharacterswithThreeMModelsEachExpectedData = { base: { url: "/assets/avatar/parts/SK_Outfit_Body_Male.glb" }, parts: [ - { url: "/assets/avatar/parts/SK_Outfit_Hat_02.glb" }, + { url: "/assets/avatar/parts/SK_Outfit_Hat_02.glb", socket: undefined }, { url: "/assets/avatar/parts/SK_Outfit_Two_Long_Coat_with_Collared_Shirt_01.glb", + socket: undefined, }, { url: "/assets/avatar/parts/SK_Outfit_Three_Tight_Jeans_with_Chain_01.glb", + socket: undefined, }, - { url: "/assets/avatar/parts/SK_Outfit_One_High_Tops_01.glb" }, + { url: "/assets/avatar/parts/SK_Outfit_One_High_Tops_01.glb", socket: undefined }, ], }; @@ -119,12 +125,14 @@ export const twoInvalidlyWrappedMModel = ` export const twoInvalidlyWrappedMModelExpectedData = { base: { url: "/assets/avatar/parts/SK_Outfit_Body_Male.glb" }, parts: [ - { url: "/assets/avatar/parts/SK_Outfit_Hat_02.glb" }, + { url: "/assets/avatar/parts/SK_Outfit_Hat_02.glb", socket: undefined }, { url: "/assets/avatar/parts/SK_Outfit_Two_Long_Coat_with_Collared_Shirt_adsfadsfasdfda01.glb", + socket: undefined, }, { url: "/assets/avatar/parts/SK_Outfit_Three_Tight_Jeans_with_Chain_01.glb", + socket: undefined, }, ], }; @@ -150,15 +158,18 @@ export const twoInvalidlyWrappedMModelOnInvalidMCharacterWith2ValidMModels = ` export const twoInvalidlyWrappedMModelOnInvalidMCharacterWith2ValidMModelsExpectedData = { base: { url: "/assets/avatar/parts/SK_Outfit_Body_Male.glb" }, parts: [ - { url: "/assets/avatar/parts/SK_Outfit_Hat_02.glb" }, + { url: "/assets/avatar/parts/SK_Outfit_Hat_02.glb", socket: undefined }, { url: "/assets/avatar/parts/SK_Outfit_Two_Long_Coat_with_Collared_Shirt_adsfadsfasdfda01.glb", + socket: undefined, }, { url: "/assets/avatar/parts/SK_Outfit_Three_Tight_Jeans_with_Chain_01.glb", + socket: undefined, }, { url: "/assets/avatar/parts/SK_Outfit_Three_Tight_Jeans_with_Chain_01.glb", + socket: undefined, }, ], }; @@ -194,14 +205,16 @@ export const validMCharacterWithRedundantMModelClosingTag = ` export const validMCharacterWithRedundantMModelClosingTagExpectedData = { base: { url: "/assets/avatar/parts/SK_Outfit_Body_Male.glb" }, parts: [ - { url: "/assets/avatar/parts/SK_Outfit_Hat_02.glb" }, + { url: "/assets/avatar/parts/SK_Outfit_Hat_02.glb", socket: undefined }, { url: "/assets/avatar/parts/SK_Outfit_Two_Long_Coat_with_Collared_Shirt_01.glb", + socket: undefined, }, { url: "/assets/avatar/parts/SK_Outfit_Three_Tight_Jeans_with_Chain_01.glb", + socket: undefined, }, - { url: "/assets/avatar/parts/SK_Outfit_One_High_Tops_01.glb" }, + { url: "/assets/avatar/parts/SK_Outfit_One_High_Tops_01.glb", socket: undefined }, ], }; @@ -217,13 +230,125 @@ export const validMCharacterWithRedundantMCharacterClosingTag = ` export const validMCharacterWithRedundantMCharacterClosingTagExpectedData = { base: { url: "/assets/avatar/parts/SK_Outfit_Body_Male.glb" }, parts: [ - { url: "/assets/avatar/parts/SK_Outfit_Hat_02.glb" }, + { url: "/assets/avatar/parts/SK_Outfit_Hat_02.glb", socket: undefined }, { url: "/assets/avatar/parts/SK_Outfit_Two_Long_Coat_with_Collared_Shirt_01.glb", + socket: undefined, }, { url: "/assets/avatar/parts/SK_Outfit_Three_Tight_Jeans_with_Chain_01.glb", + socket: undefined, + }, + { url: "/assets/avatar/parts/SK_Outfit_One_High_Tops_01.glb", socket: undefined }, + ], +}; + +export const validMCharacterWithSocketAttributes = ` + + + + +`; + +export const validMCharacterWithSocketAttributesExpectedData = { + base: { url: "/assets/avatar/parts/SK_Outfit_Body_Male.glb" }, + parts: [ + { + url: "/assets/avatar/parts/SK_Outfit_Hat_02.glb", + socket: { + socket: "head", + position: { x: 0, y: 0, z: 0 }, + scale: { x: 1, y: 1, z: 1 }, + rotation: { x: 0, y: 0, z: 0 }, + }, + }, + { + url: "/assets/avatar/parts/SK_Outfit_Two_Long_Coat_with_Collared_Shirt_01.glb", + socket: { + socket: "left-hand", + position: { x: 1, y: 1, z: 1 }, + scale: { x: 1.5, y: 1.5, z: 1.5 }, + rotation: { x: 45, y: 45, z: 45 }, + }, + }, + ], +}; + +export const validMCharacterWithSocketAndPosition = ` + + + +`; + +export const validMCharacterWithSocketAndPositionExpectedData = { + base: { url: "/assets/avatar/parts/SK_Outfit_Body_Male.glb" }, + parts: [ + { + url: "/assets/avatar/parts/SK_Outfit_Hat_02.glb", + socket: { + socket: "head", + position: { x: 2, y: 3, z: 4 }, + rotation: { x: 0, y: 0, z: 0 }, + scale: { x: 1, y: 1, z: 1 }, + }, + }, + ], +}; + +export const validMCharacterWithSocketAndRotationInOneAxis = ` + + + +`; + +export const validMCharacterWithSocketAndRotationInOneAxisExpectedData = { + base: { url: "/assets/avatar/parts/SK_Outfit_Body_Male.glb" }, + parts: [ + { + url: "/assets/avatar/parts/SK_Outfit_Hat_02.glb", + socket: { + socket: "head", + position: { x: 0, y: 0, z: 0 }, + rotation: { x: 0, y: 20, z: 0 }, + scale: { x: 1, y: 1, z: 1 }, + }, + }, + ], +}; + +export const validMCharacterWithNoSocket = ` + + + +`; + +export const validMCharacterWithNoSocketExpectedData = { + base: { url: "/assets/avatar/parts/SK_Outfit_Body_Male.glb" }, + parts: [ + { + url: "/assets/avatar/parts/SK_Outfit_Hat_02.glb", + socket: undefined, }, - { url: "/assets/avatar/parts/SK_Outfit_One_High_Tops_01.glb" }, ], }; diff --git a/example/web-avatar-client/test/test-utils.ts b/packages/3d-web-avatar/test/test-utils.ts similarity index 100% rename from example/web-avatar-client/test/test-utils.ts rename to packages/3d-web-avatar/test/test-utils.ts