feat(character): add transmog module compatibility (#21)
This commit is contained in:
parent
8b1d172690
commit
7cd2748d33
6 changed files with 61 additions and 11 deletions
|
|
@ -6,6 +6,7 @@ ACORE_ARMORY_IFRAME_MODE__ENABLED=0
|
|||
ACORE_ARMORY_IFRAME_MODE__URL="https://mywebsite.com/armory"
|
||||
ACORE_ARMORY_LOAD_DBCS=1
|
||||
ACORE_ARMORY_HIDE_GAME_MASTERS=1
|
||||
ACORE_ARMORY_TRANSMOG_MODULE=0
|
||||
ACORE_ARMORY_REALMS__0__NAME="AzerothCore"
|
||||
ACORE_ARMORY_REALMS__0__REALM_ID=1
|
||||
ACORE_ARMORY_REALMS__0__AUTH_DATABASE="acore_auth"
|
||||
|
|
|
|||
|
|
@ -142,6 +142,7 @@ I also noticed that such a tool was frequently requested in the AzerothCore Disc
|
|||
| `iframeMode.url` | `ACORE_ARMORY_IFRAME_MODE__URL` | String | `"https://mywebsite.com/armory"` | Set this to the URL of the page that hosts the `iframe` |
|
||||
| `loadDbcs` | `ACORE_ARMORY_LOAD_DBCS` | Boolean | `true` | Loads the DBC data from the `data` directory into memory when starting up. It is highly recommended to set this to `true`. Only use `false` to keep memory usage low, on a test server for example |
|
||||
| `hideGameMasters` | `ACORE_ARMORY_HIDE_GAME_MASTERS` | Boolean | `true` | Hides Game Master characters if set to `true`. They will not be found in the search page, and their character pages will show a 404 error |
|
||||
| `transmogModule` | `ACORE_ARMORY_TRANSMOG_MODULE` | Boolean | `false` | Set this to `true` if your server uses the [transmogrification module](https://github.com/azerothcore/mod-transmog) and you want to display the transmogrified items on the 3D model |
|
||||
| `realms` | `ACORE_ARMORY_REALMS__`... | Array of objects | | An array of realm configurations |
|
||||
| `realms[0].name` | `ACORE_ARMORY_REALMS__0__NAME` | String | `"AzerothCore"` | The name of the realm. Will be used in the URLs, shown on the character pages and in the search page if you have multiple realms |
|
||||
| `realms[0].realmId` | `ACORE_ARMORY_REALMS__0__REALM_ID` | Number | `1` | The realm's ID, this must match the `id` column of the `realmlist` table in the auth database |
|
||||
|
|
@ -182,8 +183,8 @@ Open a web browser and navigate to http://localhost:48733
|
|||
Other useful npm scripts:
|
||||
* `npm run clean`: cleans the build directory
|
||||
* `npm run watch`: watches for changes and rebuilds automatically, useful for development
|
||||
* `npm run fetchdata`: downloads the data needed by the 3d model viewer
|
||||
* `npm run cleardata`: clears the data downloaded for the 3d model viewer
|
||||
* `npm run fetchdata`: downloads the data needed by the 3D model viewer
|
||||
* `npm run cleardata`: clears the data downloaded for the 3D model viewer
|
||||
|
||||
### With Docker
|
||||
|
||||
|
|
@ -259,7 +260,7 @@ This repository is used in production over at [ChromieCraft](https://www.chromie
|
|||
- [X] Character page
|
||||
- [X] Online/offline status
|
||||
- [X] Equipment with tooltips
|
||||
- [X] 3d model, including mounts
|
||||
- [X] 3D model, including mounts and [transmogrifications](https://github.com/azerothcore/mod-transmog)
|
||||
- [X] Talent trees, including glyphs and dual spec support
|
||||
- [X] Achievements
|
||||
- [X] PvP statistics, including arena teams
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
},
|
||||
"loadDbcs": true,
|
||||
"hideGameMasters": true,
|
||||
"transmogModule": false,
|
||||
"realms": [
|
||||
{
|
||||
"name": "AzerothCore",
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ export class Config {
|
|||
public iframeMode: IIframeModeConfig;
|
||||
public loadDbcs: boolean;
|
||||
public hideGameMasters: boolean;
|
||||
public transmogModule: boolean;
|
||||
public realms: IRealmConfig[];
|
||||
public worldDatabase: IDatabaseConfig;
|
||||
public dbQueryTimeout: number;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ interface IEquipmentData {
|
|||
classId: number;
|
||||
subclassId: number;
|
||||
quality: number;
|
||||
transmog?: number;
|
||||
}
|
||||
|
||||
interface ICustomizationOption {
|
||||
|
|
@ -120,7 +121,7 @@ export class CharacterController {
|
|||
}
|
||||
|
||||
this.itemSocketBonuses = {};
|
||||
let [rows, fields] = await this.armory.worldDb.query({
|
||||
const [rows, fields] = await this.armory.worldDb.query({
|
||||
sql: "SELECT entry, socketBonus FROM item_template WHERE socketBonus <> 0",
|
||||
timeout: this.armory.config.dbQueryTimeout,
|
||||
});
|
||||
|
|
@ -180,6 +181,8 @@ export class CharacterController {
|
|||
return row;
|
||||
});
|
||||
const mounts = await this.getMounts(realmName, charData.guid);
|
||||
const transmogs: number[][] = this.armory.config.transmogModule ? [] : undefined;
|
||||
const characterModelItems = await this.getModelViewerItems(equipmentData, charData.class, transmogs);
|
||||
|
||||
res.render("character.hbs", {
|
||||
title: `Armory - ${charData.name}`,
|
||||
|
|
@ -189,7 +192,8 @@ export class CharacterController {
|
|||
gender: charData.gender,
|
||||
class: charData.class,
|
||||
flags: charData.playerFlags,
|
||||
characterModelItems: await this.getModelViewerItems(equipmentData, charData.class),
|
||||
characterModelItems,
|
||||
characterModelTransmogs: transmogs,
|
||||
customizationOptions: customization,
|
||||
equipment,
|
||||
mounts,
|
||||
|
|
@ -332,11 +336,16 @@ export class CharacterController {
|
|||
}
|
||||
|
||||
private async getEquipmentData(realm: string, charGuid: number): Promise<IEquipmentData[]> {
|
||||
const transmogSelect = this.armory.config.transmogModule ? ", custom_transmogrification.FakeEntry AS transmog" : "";
|
||||
const transmogJoin = this.armory.config.transmogModule ? "LEFT JOIN custom_transmogrification ON custom_transmogrification.GUID = item_instance.guid" : "";
|
||||
let [rows, fields] = await this.armory.getCharactersDb(realm).query({
|
||||
sql: `
|
||||
SELECT character_inventory.slot, item_instance.itemEntry, item_instance.flags, item_instance.enchantments, item_instance.randomPropertyId
|
||||
SELECT
|
||||
character_inventory.slot, item_instance.itemEntry, item_instance.flags, item_instance.enchantments, item_instance.randomPropertyId
|
||||
${transmogSelect}
|
||||
FROM character_inventory
|
||||
JOIN item_instance ON item_instance.guid = character_inventory.item
|
||||
${transmogJoin}
|
||||
WHERE character_inventory.guid = ? AND character_inventory.bag = 0 AND character_inventory.slot IN (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18)
|
||||
`,
|
||||
values: [charGuid],
|
||||
|
|
@ -378,7 +387,7 @@ export class CharacterController {
|
|||
return (rows as RowDataPacket[]).map((row) => this.mountBySpellId[row.spell]).filter((m) => m !== undefined);
|
||||
}
|
||||
|
||||
private async getModelViewerItems(equipmentData: IEquipmentData[], charClass: number): Promise<number[][]> {
|
||||
private async getModelViewerItems(equipmentData: IEquipmentData[], charClass: number, transmogOut?: number[][]): Promise<number[][]> {
|
||||
if (charClass !== 3) {
|
||||
// Keep ranged weapon only if the character is a hunter
|
||||
equipmentData = equipmentData.filter((row) => row.slot !== 17);
|
||||
|
|
@ -395,12 +404,27 @@ export class CharacterController {
|
|||
if (modifiedAppearance === undefined) {
|
||||
continue;
|
||||
}
|
||||
const appearance = await this.armory.dbc.itemAppearance().find((row) => row.id === modifiedAppearance.itemAppearanceId);
|
||||
let appearance = await this.armory.dbc.itemAppearance().find((row) => row.id === modifiedAppearance.itemAppearanceId);
|
||||
if (appearance === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
items.push([this.itemInventoryTypes[equipment.itemEntry], appearance.itemDisplayInfoId]);
|
||||
let invType = this.itemInventoryTypes[equipment.itemEntry];
|
||||
items.push([invType, appearance.itemDisplayInfoId]);
|
||||
|
||||
if (transmogOut !== undefined) {
|
||||
if (equipment.transmog !== undefined) {
|
||||
const modifiedAppearance = await this.armory.dbc.itemModifiedAppearance().find((row) => row.itemId === equipment.transmog);
|
||||
if (modifiedAppearance !== undefined) {
|
||||
const tmogAppearance = await this.armory.dbc.itemAppearance().find((row) => row.id === modifiedAppearance.itemAppearanceId);
|
||||
if (tmogAppearance !== undefined) {
|
||||
appearance = tmogAppearance;
|
||||
invType = this.itemInventoryTypes[equipment.transmog];
|
||||
}
|
||||
}
|
||||
}
|
||||
transmogOut.push([invType, appearance.itemDisplayInfoId]);
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
|
|
|
|||
|
|
@ -43,6 +43,12 @@
|
|||
<input id="cb-hide-tabard" type="checkbox">
|
||||
Hide tabard
|
||||
</label>
|
||||
<br>
|
||||
|
||||
<label class="checkbox">
|
||||
<input id="cb-hide-transmogs" type="checkbox">
|
||||
Hide transmogrifications
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div id="mounts-container" class="column">
|
||||
|
|
@ -125,6 +131,20 @@
|
|||
const hide = $("#cb-hide-tabard").prop("checked");
|
||||
setSlotVisible(19, !hide);
|
||||
});
|
||||
if (charData.characterModelTransmogs === undefined) {
|
||||
$("#cb-hide-transmogs").parent().hide();
|
||||
}
|
||||
$("#cb-hide-transmogs").change(() => {
|
||||
const hide = $("#cb-hide-transmogs").prop("checked");
|
||||
const items = hide ? charData.characterModelItems : charData.characterModelTransmogs;
|
||||
for (const slot of (items.map((item) => item[0]))) {
|
||||
clearSlots([slot]);
|
||||
}
|
||||
|
||||
const hideHelm = $("#cb-hide-helmet").prop("checked");
|
||||
const hideCloak = $("#cb-hide-cloak").prop("checked");
|
||||
setItems(items.filter(item => !((item[0] === 1 && hideHelm) || (item[0] === 16 && hideCloak))));
|
||||
});
|
||||
|
||||
let viewer;
|
||||
function createViewer() {
|
||||
|
|
@ -138,7 +158,9 @@
|
|||
|
||||
function setSlotVisible(slot, visible) {
|
||||
if (visible) {
|
||||
const item = charData.characterModelItems.find(([sl, appearance]) => sl === slot);
|
||||
const transmogged = !$("#cb-hide-transmogs").prop("checked");
|
||||
const items = transmogged ? charData.characterModelTransmogs : charData.characterModelItems;
|
||||
const item = items.find(([sl, appearance]) => sl === slot);
|
||||
if (item !== undefined) {
|
||||
setItems([item]);
|
||||
}
|
||||
|
|
@ -343,7 +365,7 @@
|
|||
sheathOff: -1,
|
||||
},
|
||||
cls: charData.class,
|
||||
items: charData.characterModelItems.filter(item => !((item[0] === 1 && hideHelm) || (item[0] === 16 && hideCloak))),
|
||||
items: (charData.characterModelTransmogs ?? charData.characterModelItems).filter(item => !((item[0] === 1 && hideHelm) || (item[0] === 16 && hideCloak))),
|
||||
models: {
|
||||
type: ZamModelViewer.Wow.Types.CHARACTER,
|
||||
id: `${races[charData.race]}${genders[charData.gender]}`,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue