Skip to content

Commit

Permalink
feat(assets): drastically improve asset load speed by caching sprites…
Browse files Browse the repository at this point in the history
…heet urls. closes #10
  • Loading branch information
seiyria committed Jun 27, 2023
1 parent 4b50d8f commit 45783ee
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 21 deletions.
10 changes: 6 additions & 4 deletions client/src/app/components/icon/icon.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import {
} from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { Select } from '@ngxs/store';
import { AssetService } from '@services/asset.service';
import { OptionsStore } from '@stores';
import { Observable } from 'rxjs';
import { ImageService } from '../../services/image.service';

@Component({
selector: 'app-icon',
Expand All @@ -26,32 +26,34 @@ export class IconComponent implements OnInit, OnChanges {
@Input({ required: true }) sprite!: number;
@Input() size: 'small' | 'normal' = 'normal';

private hasLoaded = false;
private quality = 'medium';

public spritesheetUrl!: any;
public assetLocation = '-0px -0px';

constructor(private imageService: ImageService) {}
constructor(private assetService: AssetService) {}

async ngOnInit() {
this.quality$
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((res: any) => {
this.quality = res;
this.updateSprite();
this.hasLoaded = true;
});
}

async ngOnChanges() {
if (!this.hasLoaded) return;
this.updateSprite();
}

private async updateSprite() {
this.spritesheetUrl = await this.imageService.getImageUrl(
this.spritesheetUrl = this.assetService.getSpritesheetUrl(
this.spritesheet,
this.quality,
);

this.assetLocation = this.getSpriteLocation();
}

Expand Down
52 changes: 35 additions & 17 deletions client/src/app/services/asset.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Injectable } from '@angular/core';
import { BackgroundImageService } from '@services/backgroundimage.service';
import { lastValueFrom } from 'rxjs';
import { environment } from '../../environments/environment';
import { ImageService } from './image.service';

Expand All @@ -10,6 +11,8 @@ export class AssetService {
private maxPortraits = 0;
private maxBackgrounds = 0;

private spritesheetUrlsByQuality: Record<string, Record<string, string>> = {};

public get portraitCount(): number {
return this.maxPortraits;
}
Expand Down Expand Up @@ -61,24 +64,39 @@ export class AssetService {
{ quality: 'high', sheets: manifestData.assets.spritesheetHQ },
];

qualitiesAndSheets.forEach(({ quality, sheets }) => {
sheets.forEach(async ({ name, path, hash }: any) => {
const fullUrl = `${environment.assetsUrl}/${path}`;
await Promise.all(
qualitiesAndSheets.map(async ({ quality, sheets }) => {
await Promise.all(
sheets.map(async ({ name, path, hash }: any) => {
const fullUrl = `${environment.assetsUrl}/${path}`;

const oldImage = await this.imageService.getImageDataByUrl(fullUrl);
this.spritesheetUrlsByQuality[quality] = {};

if (!oldImage || oldImage.hash !== hash) {
this.imageService.fetchImage(fullUrl).subscribe((blob) => {
this.imageService.saveImageToDatabase(
name,
hash,
quality,
fullUrl,
blob,
);
});
}
});
});
const oldImage = await this.imageService.getImageDataByUrl(fullUrl);

if (!oldImage || oldImage.hash !== hash) {
const blob = await lastValueFrom(
this.imageService.fetchImage(fullUrl),
);

await this.imageService.saveImageToDatabase(
name,
hash,
quality,
fullUrl,
blob,
);
}

const url = await this.imageService.getSafeImageUrl(name, quality);
this.spritesheetUrlsByQuality[quality][name] = url;
}),
);
}),
);
}

public getSpritesheetUrl(name: string, quality: string): string {
return this.spritesheetUrlsByQuality[quality][name];
}
}
5 changes: 5 additions & 0 deletions client/src/app/services/image.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ export class ImageService {
return readImageByURL(url);
}

async getSafeImageUrl(name: string, quality: string) {
const baseUrl = await this.getImageUrl(name, quality);
return (baseUrl as any).changingThisBreaksApplicationSecurity;
}

async getImageUrl(name: string, quality: string) {
const blob = await readImagesByNameAndQuality(name, quality);
if (!blob) {
Expand Down

0 comments on commit 45783ee

Please sign in to comment.