Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[+] Chuni Userbox with Assets #97

Merged
merged 7 commits into from
Jan 1, 2025
Merged

Conversation

raymonable
Copy link
Contributor

@raymonable raymonable commented Jan 1, 2025

it's finally done

a few notes:

  • chinese translations need to be filled in
  • there are known issues in safari
  • no profile userbox support until the API to access the items of other people's userboxes is added
  • trophy colors are incorrect because it's unavailable in the API, scraping game files for it could be feasible but isn't implemented right now
  • fallback for avatar clothing being missing in files is the default wear, may confuse some players?

Summary by Sourcery

实现带有铭牌和头像自定义的Chuni用户框显示。

新功能:

  • 显示可自定义铭牌和头像的Chuni用户框。

测试:

  • 为新的用户框功能添加UI元素。
Original summary in English

Summary by Sourcery

Implement Chuni userbox display with nameplate and avatar customization.

New Features:

  • Display Chuni userboxes with customizable nameplates and avatars.

Tests:

  • Add UI elements for new userbox features.

Copy link
Contributor

sourcery-ai bot commented Jan 1, 2025

审阅者指南 by Sourcery

这个拉取请求实现了 Chuni 用户框功能,包括显示用户的名牌和头像的能力。它引入了新的组件,利用 IndexedDB 存储 DDS 资源,并在设置菜单中添加了新的选项。

DDS 和用户框实现的类图

classDiagram
    class DDS {
        -canvas2D: HTMLCanvasElement
        -canvasGL: HTMLCanvasElement
        -urlCache: Record<string, string>
        -ctx: CanvasRenderingContext2D
        -gl: WebGLRenderingContext
        -ext: WebGLExtension
        -shader: WebGLShader
        -db: IDBDatabase
        +load(buffer: Uint8Array)
        +getBlob(inFormat?: string): Promise<Blob>
        +fromBlob(input: Blob)
        +loadFile(path: string): Promise<boolean>
        +getFile(path: string, fallback?: string): Promise<string>
        -compileShaders()
    }

    class ChuniPenguinComponent {
        +chuniWear: number
        +chuniHead: number
        +chuniFace: number
        +chuniSkin: number
        +chuniItem: number
        +chuniFront: number
        +chuniBack: number
        +classPassthrough: string
    }

    class ChuniUserplateComponent {
        +chuniLevel: number
        +chuniName: string
        +chuniRating: number
        +chuniNameplate: number
        +chuniCharacter: number
        +chuniTrophyName: string
    }

    DDS <-- ChuniPenguinComponent : uses
    DDS <-- ChuniUserplateComponent : uses
Loading

文件级变更

变更 详情 文件
实现 Chuni 用户框功能
  • 添加了用于渲染用户牌和企鹅头像的新组件。
  • 集成 IndexedDB 以高效存储和检索 DDS 资源。
  • 实现了处理用户提供的游戏数据的文件处理逻辑。
  • 添加了启用/禁用用户框和更新资源的新设置选项。
  • 更新了 UI 元素以适应新的用户框功能。
  • 添加了错误处理和用户反馈机制。
AquaNet/src/components/settings/ChuniSettings.svelte
国际化支持
  • 为新的用户框功能和设置选项添加了英语和中文翻译。
  • 更新了翻译键以确保不同语言的一致性。
AquaNet/src/libs/i18n/en_ref.ts
AquaNet/src/libs/i18n/zh.ts
数据处理
  • 向 UserBox 接口添加了新字段以存储等级和玩家评分信息。
  • 更新了数据结构以支持新的用户框功能。
AquaNet/src/libs/generalTypes.ts
DDS 文件处理
  • 实现了用于处理 Chuni 用户框资源的简化 DDS 解析器。
  • 添加了对不同压缩模式和纹理格式的支持。
  • 实现了加载、导出和操作 DDS 文件的函数。
  • 添加了错误处理和浏览器兼容性检查。
AquaNet/src/libs/userbox/dds.ts
用户框实用函数
  • 实现了文件处理、验证和 IndexedDB 交互的实用函数。
  • 添加了扫描和提取用户提供的游戏文件夹数据的支持。
  • 实现了进度更新机制,以在文件处理期间提供用户反馈。
AquaNet/src/libs/userbox/userbox.ts
UI 组件实现
  • 创建了用于渲染 Chuni 企鹅头像和用户牌的新 Svelte 组件。
  • 根据用户数据和 DDS 资源实现了动态图像加载和渲染。
  • 添加了样式和动画以增强用户框元素的视觉呈现。
  • 实现了选择和更新用户框项目的用户交互逻辑。
AquaNet/src/components/settings/userbox/ChuniPenguin.svelte
AquaNet/src/components/settings/userbox/ChuniUserplate.svelte

提示和命令

与 Sourcery 交互

  • 触发新的审阅: 在拉取请求中评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审阅评论。
  • 从审阅评论生成 GitHub 问题: 通过回复评论要求 Sourcery 创建问题。
  • 生成拉取请求标题: 在拉取请求标题中的任何位置写 @sourcery-ai 以随时生成标题。
  • 生成拉取请求摘要: 在拉取请求正文中的任何位置写 @sourcery-ai summary 以随时生成 PR 摘要。您还可以使用此命令指定摘要的插入位置。

自定义您的体验

访问您的仪表板以:

  • 启用或禁用审阅功能,如 Sourcery 生成的拉取请求摘要、审阅者指南等。
  • 更改审阅语言。
  • 添加、删除或编辑自定义审阅说明。
  • 调整其他审阅设置。

获取帮助

Original review guide in English

Reviewer's Guide by Sourcery

This pull request implements the Chuni userbox feature, including the ability to display user's nameplates and avatars. It introduces new components, utilizes IndexedDB for storing DDS assets, and adds new options in the settings menu.

Class diagram for DDS and Userbox implementation

classDiagram
    class DDS {
        -canvas2D: HTMLCanvasElement
        -canvasGL: HTMLCanvasElement
        -urlCache: Record<string, string>
        -ctx: CanvasRenderingContext2D
        -gl: WebGLRenderingContext
        -ext: WebGLExtension
        -shader: WebGLShader
        -db: IDBDatabase
        +load(buffer: Uint8Array)
        +getBlob(inFormat?: string): Promise<Blob>
        +fromBlob(input: Blob)
        +loadFile(path: string): Promise<boolean>
        +getFile(path: string, fallback?: string): Promise<string>
        -compileShaders()
    }

    class ChuniPenguinComponent {
        +chuniWear: number
        +chuniHead: number
        +chuniFace: number
        +chuniSkin: number
        +chuniItem: number
        +chuniFront: number
        +chuniBack: number
        +classPassthrough: string
    }

    class ChuniUserplateComponent {
        +chuniLevel: number
        +chuniName: string
        +chuniRating: number
        +chuniNameplate: number
        +chuniCharacter: number
        +chuniTrophyName: string
    }

    DDS <-- ChuniPenguinComponent : uses
    DDS <-- ChuniUserplateComponent : uses
Loading

File-Level Changes

Change Details Files
Implement Chuni Userbox Feature
  • Added new components for rendering the userplate and penguin avatar.
  • Integrated IndexedDB for efficient storage and retrieval of DDS assets.
  • Implemented file processing logic for handling user-provided game data.
  • Added new settings options for enabling/disabling the userbox and updating assets.
  • Updated UI elements to accommodate the new userbox features.
  • Added error handling and user feedback mechanisms.
AquaNet/src/components/settings/ChuniSettings.svelte
Internationalization Support
  • Added English and Chinese translations for the new userbox feature and settings options.
  • Updated translation keys to ensure consistency across different languages.
AquaNet/src/libs/i18n/en_ref.ts
AquaNet/src/libs/i18n/zh.ts
Data Handling
  • Added new fields to the UserBox interface to store level and player rating information.
  • Updated data structures to support the new userbox features.
AquaNet/src/libs/generalTypes.ts
DDS File Handling
  • Implemented a simplified DDS parser for handling Chuni userbox assets.
  • Added support for different compression modes and texture formats.
  • Implemented functions for loading, exporting, and manipulating DDS files.
  • Added error handling and browser compatibility checks.
AquaNet/src/libs/userbox/dds.ts
Userbox Utility Functions
  • Implemented utility functions for file processing, validation, and IndexedDB interaction.
  • Added support for scanning and extracting data from user-provided game folders.
  • Implemented progress update mechanisms to provide user feedback during file processing.
AquaNet/src/libs/userbox/userbox.ts
UI Component Implementation
  • Created new Svelte components for rendering the Chuni penguin avatar and userplate.
  • Implemented dynamic image loading and rendering based on user data and DDS assets.
  • Added styling and animations to enhance the visual presentation of the userbox elements.
  • Implemented user interaction logic for selecting and updating userbox items.
AquaNet/src/components/settings/userbox/ChuniPenguin.svelte
AquaNet/src/components/settings/userbox/ChuniUserplate.svelte

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time. You can also use
    this command to specify where the summary should be inserted.

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

@raymonable - 我已经审查了你的更改 - 以下是一些反馈:

整体评论

  • 在合并之前需要解决Safari兼容性问题,因为它是一个主要的浏览器平台
  • 请为所有新字符串添加缺失的中文翻译
以下是我在审查期间查看的内容
  • 🟢 一般问题:一切看起来都很好
  • 🟢 安全性:一切看起来都很好
  • 🟢 测试:一切看起来都很好
  • 🟡 复杂性:发现1个问题
  • 🟢 文档:一切看起来都很好

Sourcery 对开源项目是免费的 - 如果你喜欢我们的评论,请考虑分享它们 ✨
帮助我变得更有用!请在每条评论上点击 👍 或 👎,我将使用这些反馈来改进你的评论。
Original comment in English

Hey @raymonable - I've reviewed your changes - here's some feedback:

Overall Comments:

  • Safari compatibility issues need to be resolved before merging as it's a major browser platform
  • Please add the missing Chinese translations for all new strings
Here's what I looked at during the review
  • 🟢 General issues: all looks good
  • 🟢 Security: all looks good
  • 🟢 Testing: all looks good
  • 🟡 Complexity: 1 issue found
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@@ -0,0 +1,314 @@
/*
Copy link
Contributor

Choose a reason for hiding this comment

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

问题(复杂性): 考虑将缓存逻辑提取到一个单独的类中,以简化DDS类并实现缓存行为的独立测试。

混合缓存逻辑和DDS加载/渲染会增加不必要的复杂性。考虑将缓存提取到一个单独的类:

class DDSCache {
    private urlCache: Record<string, string> = {};
    constructor(private db?: IDBDatabase) {}

    async loadFromDB(path: string): Promise<Blob | null> {
        if (!this.db) return null;
        const transaction = this.db.transaction(["dds"], "readonly");
        const request = transaction.objectStore("dds").get(path);

        return new Promise((resolve) => {
            request.onsuccess = () => resolve(request.result?.blob ?? null);
            request.onerror = () => resolve(null);
        });
    }

    getCachedUrl(path: string): string | undefined {
        return this.urlCache[path];
    }

    cacheUrl(path: string, url: string) {
        this.urlCache[path] = url;
    }
}

然后通过注入缓存来简化DDS类:

export class DDS {
    constructor(private cache: DDSCache) {
        this.initializeWebGL();
    }

    async getFile(path: string, fallback?: string): Promise<string> {
        const cached = this.cache.getCachedUrl(path);
        if (cached) return cached;

        const loaded = await this.loadAndRender(path) || 
                      (fallback && await this.loadAndRender(fallback));
        if (!loaded) return ""

        const url = URL.createObjectURL(await this.getBlob("image/png") ?? new Blob([]))
        this.cache.cacheUrl(path, url);
        return url;
    }

    private async loadAndRender(path: string): Promise<boolean> {
        const blob = await this.cache.loadFromDB(path);
        if (!blob) return false;
        await this.fromBlob(blob);
        return true;
    }
}

这种分离:

  1. 使缓存逻辑可独立测试
  2. 简化错误处理路径
  3. 保持核心DDS功能专注于解析/渲染
  4. 使修改缓存行为更加容易
Original comment in English

issue (complexity): Consider extracting the caching logic into a separate class to simplify the DDS class and enable independent testing of the caching behavior.

The mixing of caching logic with DDS loading/rendering adds unnecessary complexity. Consider extracting the caching into a separate class:

class DDSCache {
    private urlCache: Record<string, string> = {};
    constructor(private db?: IDBDatabase) {}

    async loadFromDB(path: string): Promise<Blob | null> {
        if (!this.db) return null;
        const transaction = this.db.transaction(["dds"], "readonly");
        const request = transaction.objectStore("dds").get(path);

        return new Promise((resolve) => {
            request.onsuccess = () => resolve(request.result?.blob ?? null);
            request.onerror = () => resolve(null);
        });
    }

    getCachedUrl(path: string): string | undefined {
        return this.urlCache[path];
    }

    cacheUrl(path: string, url: string) {
        this.urlCache[path] = url;
    }
}

Then simplify the DDS class by injecting the cache:

export class DDS {
    constructor(private cache: DDSCache) {
        this.initializeWebGL();
    }

    async getFile(path: string, fallback?: string): Promise<string> {
        const cached = this.cache.getCachedUrl(path);
        if (cached) return cached;

        const loaded = await this.loadAndRender(path) || 
                      (fallback && await this.loadAndRender(fallback));
        if (!loaded) return "";

        const url = URL.createObjectURL(await this.getBlob("image/png") ?? new Blob([]));
        this.cache.cacheUrl(path, url);
        return url;
    }

    private async loadAndRender(path: string): Promise<boolean> {
        const blob = await this.cache.loadFromDB(path);
        if (!blob) return false;
        await this.fromBlob(blob);
        return true;
    }
}

This separation:

  1. Makes caching logic independently testable
  2. Simplifies error handling paths
  3. Keeps core DDS functionality focused on parsing/rendering
  4. Makes it easier to modify caching behavior

@raymonable
Copy link
Contributor Author

image

@nbitzz
Copy link
Contributor

nbitzz commented Jan 1, 2025

Hi, question: are the postinstall scripts from @parcel/watcher supposed to be left untrusted, or am I just doing something wrong? I don't regularly use Bun, so need advice here.

@clansty
Copy link
Collaborator

clansty commented Jan 1, 2025

It seems that the "input url" feature is removed in i18n files. Is this feature removed?

I think we can keep both "input url" and "select game folder" and let the user to choose

@nbitzz
Copy link
Contributor

nbitzz commented Jan 1, 2025

It seems that the "input url" feature is removed in i18n files. Is this feature removed?

I think we can keep both "input url" and "select game folder" and let the user to choose

It looks like it was removed. Raymond's asleep, but since he seems to want to get this merged so quickly, I'll do my best to look at what was there previously and reimplement it myself...

@nbitzz
Copy link
Contributor

nbitzz commented Jan 1, 2025

Should the HAS_USERBOX_ASSETS {#if} block encapsulate the new AquaBox options aswell?

Edit: I've had it encapsulate the AquaBox options as well; let me know if you wish for this change to be reverted

Adds back the classic UserBox preview when AquaBox is disabled / unavailable
@clansty clansty requested a review from hykilpikonna January 1, 2025 17:59
@raymonable
Copy link
Contributor Author

raymonable commented Jan 1, 2025

It seems that the "input url" feature is removed in i18n files. Is this feature removed?

i figured not many people got use out of it being there, since there's no documentation on how to setup the files-- it isn't very useful for the average public server player

@clansty
Copy link
Collaborator

clansty commented Jan 1, 2025

i figured not many people got use out of it being there, since there's no documentation on how to setup the files-- it isn't very useful for the average public server player

I think they may only need an url published by some maybe official one in discord

raymonable and others added 2 commits January 1, 2025 15:06
moved the DDS cache from dds.ts to ddsCache.ts and added caching for scaled images

Co-authored-by: split / May <[email protected]>
@hykilpikonna
Copy link
Collaborator

Hi, question: are the postinstall scripts from @parcel/watcher supposed to be left untrusted, or am I just doing something wrong? I don't regularly use Bun, so need advice here.

Uhh I don't think it matters, like I did not run the postinstall and it worked fine.

@hykilpikonna hykilpikonna merged commit 437ed2e into MewoLab:v1-dev Jan 1, 2025
hykilpikonna added a commit that referenced this pull request Jan 2, 2025
'userbox.new.activate_update': 'Update AquaBox (game files required)',
'userbox.new.activate': 'Use AquaBox',
'userbox.new.activate_desc': 'Enable displaying UserBoxes with their nameplate & avatar',
'userbox.new.error.invalidFolder': 'The folder you selected is invalid. Ensure that your game\'s version is Lumi or newer and that the "A001" option pack is present.'
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do you mean A000?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, my mistake

export async function userboxFileProcess(folder: FileSystemEntry, progressUpdate: (progress: number, progressString: string) => void): Promise<string | null> {
if (!isDirectory(folder))
return t("userbox.new.error.invalidFolder")
if (!(await validateDirectories(folder, "bin/option")) || !(await validateDirectories(folder, "data/A000")))
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think the logic here might be incorrect. Currently it requires both of these paths to be present, but they should be optional if only one is present?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

i mean data/A000 is required 100% but bin/option might not be? but there's such an unlikely chance that someone using game data won't have an option

hykilpikonna added a commit that referenced this pull request Jan 2, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants