Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pxtlib/spriteutils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ namespace pxt.sprite {
}
}

protected dataLength() {
dataLength() {
return Math.ceil(this.width * this.height / 2);
}
}
Expand Down Expand Up @@ -179,7 +179,7 @@ namespace pxt.sprite {
this.buf[index] = value;
}

protected dataLength() {
dataLength() {
return this.width * this.height;
}
}
Expand Down
75 changes: 69 additions & 6 deletions pxtlib/tilemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,12 @@ namespace pxt {
const existing = this.lookupByID(id);

if (!assetEquals(existing, newValue)) {
if (!validateAsset(newValue) && validateAsset(existing)) {
pxt.warn("Refusing to overwrite asset with invalid version");
pxt.tickEvent("assets.invalidAssetOverwrite", { assetType: newValue.type });
return existing;
}

this.removeByID(id);
asset = this.add(newValue);
this.notifyListener(newValue.internalID);
Expand Down Expand Up @@ -1948,6 +1954,69 @@ namespace pxt {
return getShortIDCore(asset.type, asset.id);
}

export function validateAsset(asset: pxt.Asset) {
if (!asset) return false;

switch (asset.type) {
case AssetType.Image:
case AssetType.Tile:
return validateImageAsset(asset as ProjectImage | Tile);
case AssetType.Tilemap:
return validateTilemap(asset as ProjectTilemap);
case AssetType.Animation:
return validateAnimation(asset as Animation)
case AssetType.Song:
return validateSong(asset as Song);
}
}

function validateImageAsset(asset: ProjectImage | Tile) {
if (!asset.bitmap) return false;

return validateBitmap(sprite.Bitmap.fromData(asset.bitmap));
}

function validateTilemap(tilemap: ProjectTilemap) {
if (
!tilemap.data ||
!tilemap.data.tilemap ||
!tilemap.data.tileset ||
!tilemap.data.tileset.tileWidth ||
!tilemap.data.tileset.tiles?.length ||
!tilemap.data.layers
) {
return false;
}

return validateBitmap(sprite.Bitmap.fromData(tilemap.data.layers)) &&
validateBitmap(tilemap.data.tilemap);
}

function validateAnimation(animation: Animation) {
if (!animation.frames?.length || animation.interval <= 0) {
return false;
}

return !animation.frames.some(frame => !validateBitmap(sprite.Bitmap.fromData(frame)));
}

function validateBitmap(bitmap: sprite.Bitmap) {
return bitmap.width > 0 &&
bitmap.height > 0 &&
!Number.isNaN(bitmap.x0) &&
!Number.isNaN(bitmap.y0) &&
bitmap.data().data.length === bitmap.dataLength();
}

function validateSong(song: Song) {
return song.song &&
song.song.ticksPerBeat > 0 &&
song.song.beatsPerMeasure > 0 &&
song.song.measures > 0 &&
song.song.beatsPerMinute > 0 &&
!!song.song.tracks;
}

function getShortIDCore(assetType: pxt.AssetType, id: string, allowNoPrefix = false) {
let prefix: string;
switch (assetType) {
Expand Down Expand Up @@ -2062,12 +2131,6 @@ namespace pxt {
}
}


function set16Bit(buf: Uint8ClampedArray, offset: number, value: number) {
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 function supposed to be deleted?

Copy link
Member Author

Choose a reason for hiding this comment

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

yeah, it wasn't used

buf[offset] = value & 0xff;
buf[offset + 1] = (value >> 8) & 0xff;
}

function read16Bit(buf: Uint8ClampedArray, offset: number) {
return buf[offset] | (buf[offset + 1] << 8)
}
Expand Down