Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
9b91180
[Automated] Update translations 2025-05-24 (#2129)
DangoCat May 24, 2025
0a48b96
sound: Update image attributions (#2130)
ScratchFakemon May 25, 2025
8333213
[Automated] Update translations 2025-05-28 (#2133)
DangoCat May 29, 2025
f672a8d
Lily/Skins: Fix some fatal loading bugs. (#2128)
yuri-kiss May 30, 2025
a2c1aa5
build(deps): bump @turbowarp/types from `b9bcd77` to `9c201e9` (#2132)
dependabot[bot] May 30, 2025
7835a14
build(deps-dev): bump @transifex/api from 7.1.3 to 7.1.4 (#2131)
dependabot[bot] May 30, 2025
225c003
Lily/Skins: handle the rotationCenter error differently (#2137)
yuri-kiss May 30, 2025
59a0cbf
[Automated] Update translations 2025-05-31 (#2140)
DangoCat May 31, 2025
589a09e
[Automated] Update translations 2025-06-04 (#2143)
DangoCat Jun 4, 2025
774d399
Use versions instead of commit hash for official GitHub Actions workf…
GarboMuffin Jun 4, 2025
a73e6fd
CST1229/images: new image (#2144)
wiktorlaskowski Jun 4, 2025
815dbee
[Automated] Update translations 2025-06-07 (#2150)
DangoCat Jun 7, 2025
578acb9
build(deps-dev): bump eslint from 9.27.0 to 9.28.0 (#2141)
dependabot[bot] Jun 7, 2025
5aec334
build(deps): bump @turbowarp/types from `9c201e9` to `0cf07a4` (#2151)
dependabot[bot] Jun 7, 2025
ee22d92
Xeltalliv/simple3D: mark drawable as non-interactive (#2152)
GarboMuffin Jun 7, 2025
ec4d5a5
Xeltalliv/clippingblending: Fix canvas alpha compatibility and other …
Xeltalliv Jun 8, 2025
05dae3b
SharkPool/Camera: improve performance after many drawables created an…
GarboMuffin Jun 8, 2025
b7b3a48
[Automated] Update translations 2025-06-11 (#2159)
DangoCat Jun 11, 2025
f03effd
cloudlink: make every (non-localhost) server ID behave like 7 (#2164)
CST1229 Jun 14, 2025
0dafa9b
[Automated] Update translations 2025-06-14 (#2167)
DangoCat Jun 14, 2025
3daea52
Lily/ListTools: Fix 'repeat x times in list' only adding to extractor…
SharkPool-SP Jun 19, 2025
6045d70
utilities: fix letters erroring if input string is a number (#2173)
GarboMuffin Jun 19, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,19 @@ jobs:

steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Install Node.js
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af
uses: actions/setup-node@v4
with:
node-version: 22
- name: Install dependencies
run: npm ci
- name: Build for production
run: npm run build
- name: Upload artifact
uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa
uses: actions/upload-pages-artifact@v3
with:
path: ./build/

Expand All @@ -47,4 +47,4 @@ jobs:
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e
uses: actions/deploy-pages@v4
4 changes: 2 additions & 2 deletions .github/workflows/download-translations.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:

steps:
- name: Checkout fork
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
uses: actions/checkout@v4
with:
# Commits will be written to this fork, then pull requested to the main repository.
repository: "DangoCat/extensions"
Expand All @@ -35,7 +35,7 @@ jobs:
env:
UPSTREAM_REPO: "TurboWarp/extensions"
- name: Install Node.js
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af
uses: actions/setup-node@v4
with:
node-version: 22
- name: Install dependencies
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/format-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
)
steps:
- name: Checkout upstream
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
uses: actions/checkout@v4
with:
repository: TurboWarp/extensions
persist-credentials: false
Expand All @@ -35,15 +35,15 @@ jobs:
PR_NUM: "${{ github.event.issue.number }}"
GH_TOKEN: "${{ github.token }}"
- name: Install Node.js
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af
uses: actions/setup-node@v4
with:
node-version: 22
- name: Install dependencies
run: npm ci
- name: Format
run: npm run format
- name: Upload formatted code
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b
uses: actions/upload-artifact@v4
with:
name: comment-format-untrusted-artifact
path: extensions/
Expand All @@ -60,7 +60,7 @@ jobs:
pull-requests: write
steps:
- name: Checkout upstream
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
uses: actions/checkout@v4
with:
repository: TurboWarp/extensions
# Can't use the default workflow token because commits made by it won't cause more
Expand All @@ -80,7 +80,7 @@ jobs:
PR_NUM: "${{ github.event.issue.number }}"
GH_TOKEN: "${{ github.token }}"
- name: Download formatted code
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16
uses: actions/download-artifact@v4
with:
name: comment-format-untrusted-artifact
path: extensions
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/upload-translations.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ jobs:

steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Install Node.js
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af
uses: actions/setup-node@v4
with:
node-version: 22
- name: Install dependencies
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Install Node.js
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
Expand All @@ -25,11 +25,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Install Node.js
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
Expand All @@ -42,11 +42,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Install Node.js
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
Expand Down
2 changes: 1 addition & 1 deletion extensions/Lily/ListTools.js
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@
if (!list2) return;
const currentVal = list1.value;
for (let i = 0; i < args.NUM; i++) {
list1.value = list1.value.concat(currentVal);
list2.value = list2.value.concat(currentVal);
}
}

Expand Down
136 changes: 111 additions & 25 deletions extensions/Lily/Skins.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,71 @@
return true;
};

const vm = Scratch.vm;
const runtime = vm.runtime;
const renderer = runtime.renderer;
const Cast = Scratch.Cast;

const createSVGSkin = (...args) => {
const skinId = renderer.createSVGSkin(...args);
if (!skinId) return;
const svgSkin = renderer._allSkins[skinId];
if (!svgSkin) return;
// To prevent a issue in the skin loading we will override the onload event ourself.
const _onload = svgSkin._svgImage.onload;
svgSkin._svgImage.onload = /**
* @this {RenderWebGL.SVGSkin}
*/ function (ev) {
// Reimplement the begining logic of SVGSkin to fix a loading error.
if (!this._size) throw "_size race";
if (this._size[0] === 0 || this._size[1] === 0) {
Object.getPrototypeOf(
vm.renderer.exports.SVGSkin
).prototype.setEmptyImageData.call(this);
return;
}
const maxDimension = Math.ceil(Math.max(this._size[0], this._size[1]));
const rendererMax = this._renderer.maxTextureDimension;
let testScale = 2;
for (
testScale;
maxDimension * testScale <= rendererMax;
testScale = testScale * 2
) {
this._maxTextureScale = testScale;
}
this.resetMIPs();
const rotationCenter = this.calculateRotationCenter();
if (!Array.isArray(rotationCenter)) throw "rotationCenter race";
if (!Array.isArray(this._rotationCenter)) {
// This can happen if the file is loaded too fast.
// We will handle creating this ourselves to prevent a swarm of errors.
this._rotationCenter = [0, 0];
}
return _onload.call(this, ev);
}.bind(svgSkin);
return skinId;
};

/**
* @param {RenderWebGL.SVGSkin} svgSkin
* @returns {Promise<void>}
* @returns {Promise<boolean>}
*/
const svgSkinFinishedLoading = (svgSkin) =>
new Promise((resolve) => {
if (svgSkin._svgImageLoaded) {
resolve();
resolve(true);
} else {
svgSkin._svgImage.addEventListener("load", () => {
resolve();
resolve(true);
});
svgSkin._svgImage.addEventListener("error", () => {
resolve();
resolve(false);
});
}
});

const vm = Scratch.vm;
const runtime = vm.runtime;
const renderer = runtime.renderer;
const Cast = Scratch.Cast;

var createdSkins = {};
const createdSkins = Object.create(null);

class Skins {
constructor() {
Expand Down Expand Up @@ -231,6 +272,20 @@
};
}

_disposeSafe(skinId, skinName) {
if (renderer._allSkins[skinId]) renderer.destroySkin(skinId);
if (typeof skinName !== "undefined") {
if (createdSkins[skinName] !== skinId) {
throw new Error(
`Lily/Skins: skinName "${skinName}" mismatched with skinId "${skinId}". actual value of "${
skinName
}" is "${createdSkins[skinName]}". please report this to the developers`
);
}
delete createdSkins[skinName];
}
}

async registerSVGSkin(args) {
const skinName = `lms-${Cast.toString(args.NAME)}`;
const svgData = Cast.toString(args.SVG);
Expand All @@ -241,14 +296,18 @@
}

// This generally takes a few frames, so yield the block
const skinId = renderer.createSVGSkin(svgData);
const skinId = createSVGSkin(svgData);
createdSkins[skinName] = skinId;

await svgSkinFinishedLoading(renderer._allSkins[skinId]);
if (!(await svgSkinFinishedLoading(renderer._allSkins[skinId]))) {
this._disposeSafe(skinId, skinName);
return;
}

if (oldSkinId) {
this._refreshTargetsFromID(oldSkinId, false, skinId);
renderer.destroySkin(oldSkinId);
if (renderer._allSkins[oldSkinId])
this._refreshTargetsFromID(oldSkinId, false, skinId);
this._disposeSafe(oldSkinId);
}
}

Expand All @@ -275,11 +334,28 @@
}

const skinId = await this._createURLSkin(url, rotationCenter);
const skin = renderer._allSkins[skinId];
if (!skin || !skin._svgImage || !skin._svgImage.onload) {
this._disposeSafe(skinId);
return;
}
const _onload = skin._svgImage.onload;
skin._svgImage.onload = (...args) => {
try {
return _onload.apply(skin, args);
} catch (err) {
// Handle a race condition.
if (err !== "rotationCenter race") throw err;
this._disposeSafe(skinId, skinName);
return;
}
};
createdSkins[skinName] = skinId;

if (oldSkinId) {
this._refreshTargetsFromID(oldSkinId, false, skinId);
renderer.destroySkin(oldSkinId);
if (renderer._allSkins[oldSkinId])
this._refreshTargetsFromID(oldSkinId, false, skinId);
this._disposeSafe(oldSkinId);
}
}

Expand All @@ -297,8 +373,9 @@
createdSkins[skinName] = skinId;

if (oldSkinId) {
this._refreshTargetsFromID(oldSkinId, false, skinId);
renderer.destroySkin(oldSkinId);
if (renderer._allSkins[oldSkinId])
this._refreshTargetsFromID(oldSkinId, false, skinId);
this._disposeSafe(oldSkinId);
}
}

Expand All @@ -310,13 +387,18 @@
setSkin(args, util) {
const skinName = `lms-${Cast.toString(args.NAME)}`;
if (!createdSkins[skinName]) return;
const skinId = createdSkins[skinName];
// Make sure the skin we are setting still well.. exists.
if (!renderer._allSkins[skinId]) {
this._disposeSafe(skinId, skinName);
return;
}

const targetName = Cast.toString(args.TARGET);
const target = this._getTargetFromMenu(targetName, util);
if (!target) return;
const drawableID = target.drawableID;

const skinId = createdSkins[skinName];
renderer._allDrawables[drawableID].skin = renderer._allSkins[skinId];
}

Expand Down Expand Up @@ -344,7 +426,11 @@

if (!createdSkins[skinName]) return 0;
const skinId = createdSkins[skinName];
if (!skins[skinId]) return 0;
if (!skins[skinId]) {
// If the skin doesnt exist in the renderer we should probably just delete it on our end...
this.safeDispose(skinId, skinName);
return 0;
}

const size = skins[skinId].size;
const attribute = Cast.toString(args.ATTRIBUTE).toLowerCase();
Expand All @@ -366,14 +452,14 @@

this._refreshTargetsFromID(skinId, true);
renderer.destroySkin(skinId);
Reflect.deleteProperty(createdSkins, skinName);
delete createdSkins[skinName];
}

deleteAllSkins() {
this._refreshTargets();
for (const skinName in createdSkins)
renderer.destroySkin(createdSkins[skinName]);
createdSkins = {};
for (const skinName in createdSkins) {
this._disposeSafe(createdSkins[skinName], skinName);
}
}

restoreTargets(args) {
Expand Down Expand Up @@ -431,7 +517,7 @@

const contentType = imageData.headers.get("Content-Type");
if (contentType === "image/svg+xml") {
return renderer.createSVGSkin(await imageData.text(), rotationCenter);
return createSVGSkin(await imageData.text(), rotationCenter);
} else if (
contentType === "image/png" ||
contentType === "image/jpeg" ||
Expand Down
Loading
Loading