Skip to content

Commit

Permalink
Feature/add classic (#60)
Browse files Browse the repository at this point in the history
* add getImageExtension

* manage classic views

* add classic doc

* change port to be aligned with demo
  • Loading branch information
Miorey authored Jun 26, 2024
1 parent f626303 commit 4b74f4d
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 52 deletions.
95 changes: 62 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ This library allows eu to generate a 3d model character with his customization a
use [Wowhead](https://classic.wowhead.com/) libraries to generate the rendering. This lib works with WotLK and Retail wow versions.

## 🛠 Requirements
To utilize this library effectively, you need a copy of specific files sourced from Wowhead. While there are various methods
To utilize this library effectively, you need a copy of specific files sourced from Wowhead. While there are various methods
to obtain these files, this document demonstrates the use of a replica server.

> ⚠️ Warning: The gaming data belongs to Wowhead. It's recommended to use them for personal purposes or small-scale projects, and definitely not for large commercial endeavors.
### CORS policies
Bypass using a replica server. This lib calls the replica, which fetches files from the gaming repository.
For this purpose, you can use [bypass-cors-policies](https://github.com/Miorey/bypass-cors-policies), which is specifically designed for such use cases.
For this purpose, you can use [bypass-cors-policies](https://github.com/Miorey/bypass-cors-policies), which is specifically designed for such use cases.
You can use it with docker or node.js.

#### 🐳 Using Docker
Expand Down Expand Up @@ -50,7 +50,7 @@ Regarding the `viewer.min.js` you can download it from zaming or from your local
```
AND
```html
<script src="http://localhost:2999/modelviewer/live/viewer/viewer.min.js"></script>
<script src="http://localhost:3000/modelviewer/live/viewer/viewer.min.js"></script>
```
OR
```html
Expand All @@ -60,8 +60,8 @@ OR
### Setup

#### WotLK or Retail ?
The library works well with both retail and WotLK.
For WotLK, some adjustments need to be made.
The library works well with both retail and WotLK.
For WotLK, some adjustments need to be made.
By default, the library is set up to work with WotLK by using this URL to retrieve the display ID for old items.
```js
window.WOTLK_TO_RETAIL_DISPLAY_ID_API=`https://wotlk.murlocvillage.com/api/items`
Expand All @@ -74,12 +74,12 @@ When you want to use the lib for wow retail you just need to set this var to `un

#### Data Path

Lastly, you must set up the `CONTENT_PATH` environment variable.
This indicates the location of the data required to render the canvas.
Lastly, you must set up the `CONTENT_PATH` environment variable.
This indicates the location of the data required to render the canvas.
If you're using the provided `docker-compose` example, then:

```js
window.CONTENT_PATH = `http://localhost:2999/modelviewer/live/`
window.CONTENT_PATH = `http://localhost:3000/modelviewer/live/`
```


Expand Down Expand Up @@ -157,7 +157,7 @@ To load the character my beautiful female gnome warlock
<script src="https://code.jquery.com/jquery-3.5.1.min.js"
integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0="
crossorigin="anonymous"></script>
<script src="http://localhost:2999/modelviewer/live/viewer/viewer.min.js"></script>
<script src="http://localhost:3000/modelviewer/live/viewer/viewer.min.js"></script>
<script type="module" src="./index.js"></script>
</head>
<body>
Expand Down Expand Up @@ -191,14 +191,14 @@ The description of the character is

```json
{
"race":7,
"gender":1,
"skin":4,
"face":0,
"hairStyle":5,
"hairColor":5,
"facialStyle":5,
"items": [[1,1170],[3,4925],[5,9575],[6,25235],[7,2311],[8,21154],[9,14618],[10,9534],[15,17238],[21,20379],[22,28787]]
"race":7,
"gender":1,
"skin":4,
"face":0,
"hairStyle":5,
"hairColor":5,
"facialStyle":5,
"items": [[1,1170],[3,4925],[5,9575],[6,25235],[7,2311],[8,21154],[9,14618],[10,9534],[15,17238],[21,20379],[22,28787]]
}
```

Expand Down Expand Up @@ -386,32 +386,61 @@ To get the npc display ids you can go [here](https://wow.tools/dbc/?dbc=creature

Prince of Lordaeron:
```js
const model = await generateModels(1, `#model_3d`, {type: 8, id: 24949});
const model = await generateModels(1, `#model_3d`, {type: modelingType.NPC, id: 24949});
```

To display Atiesh, Greatstaff of the Guardian
```js
const model = await generateModels(1, `#model_3d`, {type: 1, id: 193841});
const model = await generateModels(1, `#model_3d`, {type: modelingType.ITEM, id: 193841});
```

#### Table of types

Description | Type
:--------------:|:----:|
Item | 1 |
Helm | 2 |
Shoulder | 4 |
NPC | 8 |
Character | 16 |
Humanoidnpc | 32 |
Object | 64 |
Armor | 128 |
Path | 256 |
Itemvisual | 512 |
Collection | 102 |
Description | Type | `modelingType` |
:--------------:|:----:|:-----------------:|
Item | 1 | `.ITEM` |
Helm | 2 | `.HELM` |
Shoulder | 4 | `.SHOULDER` |
NPC | 8 | `.NPC` |
Character | 16 | `.CHARACTER` |
Humanoidnpc | 32 | `.HUMANOIDNPC` |
Object | 64 | `.OBJECT` |
Armor | 128 | `.ARMOR` |
Path | 256 | `.PATH` |
Itemvisual | 512 | `.ITEMVISUAL` |
Collection | 1024 | `.COLLECTION` |

### Classic character display.
To display the character of WoW classic you need to change your scripts:
```html
<script src="http://localhost:3000/modelviewer/classic/viewer/viewer.min.js"></script>
```
and change following vars to:
```js
window.CONTENT_PATH = `http://localhost:3000/modelviewer/classic/`
window.WOTLK_TO_RETAIL_DISPLAY_ID_API = undefined
```
when you call `generateModels` you need to add a new param at the end `"classic"`

```js
generateModels(1.5, `#model_3d1`, character, "classic");
```
⚠️For some items you can't display them with a customize character look, in this case you need to use
a new option `"noCharCustomization": true`.

Ex:
```js
const character2 = {
"race": 1,
"gender": 0,
"items": [[21, 679611]],
"noCharCustomization": true
}
window.model2 = await generateModels(1.5, `#model_3d2`, character2, "classic");
```

# Updates
As this library is based on a minified version of the Wowhead model viewer, regular upgrades of this library may require you to clear your cached data.
As this library is based on a minified version of the Wowhead model viewer, regular upgrades of this library may require you to clear your cached data.
If you are using a Docker `bypass-cors-policies` container, you can follow these steps to clean up the cache:

```sh
Expand Down
47 changes: 35 additions & 12 deletions character_modeling.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,20 @@ const NOT_DISPLAYED_SLOTS = [
14, // trinket2
]

const modelingType = {
ARMOR: 128,
CHARACTER: 16,
COLLECTION: 1024,
HELM: 2,
HUMANOIDNPC: 32,
ITEM: 1,
ITEMVISUAL: 512,
NPC: 8,
OBJECT: 64,
PATH: 256,
SHOULDER: 4
}

const characterPart = () => {
const ret = {
Face: `face`,
Expand Down Expand Up @@ -108,18 +122,20 @@ function optionsFromModel(model, fullOptions) {
// slot ids on model viewer
const characterItems = (model.items) ? model.items.filter(e => !NOT_DISPLAYED_SLOTS.includes(e[0])) : []
const options = getCharacterOptions(model, fullOptions)


return {
let charCustomization = {
options: options
}
const ret = {
items: characterItems,
charCustomization: {
options: options
},
models: {
id: race*2-1+gender,
type: 16
type: modelingType.CHARACTER
},
}
if(!model.noCharCustomization) {
ret.charCustomization = charCustomization
}
return ret
}


Expand All @@ -129,9 +145,10 @@ function optionsFromModel(model, fullOptions) {
* @param item{number}: Item id
* @param slot{number}: Item slot number
* @param displayId{number}: DisplayId of the item
* @param env {('classic'|'live')}: select game env
* @return {Promise<boolean|*>}
*/
async function getDisplaySlot(item, slot, displayId) {
async function getDisplaySlot(item, slot, displayId, env=`live`) {
if (typeof item !== `number`) {
throw new Error(`item must be a number`)
}
Expand All @@ -145,7 +162,10 @@ async function getDisplaySlot(item, slot, displayId) {
}

try {
await fetch(`${window.CONTENT_PATH}meta/armor/${slot}/${displayId}.json`)
const jsonPath = (env === `classic` && [21, 22].includes(slot)) ?
`${window.CONTENT_PATH}meta/item/${displayId}.json` :
`${window.CONTENT_PATH}meta/armor/${slot}/${displayId}.json`
await fetch(jsonPath)
.then(response => response.json())

return {
Expand Down Expand Up @@ -195,9 +215,10 @@ async function getDisplaySlot(item, slot, displayId) {
* Returns a 2-dimensional list the inner list contains on first position the item slot, the second the item
* display-id ex: [[1,1170],[3,4925]]
* @param {*[{item: {entry: number, displayid: number}, transmog: {entry: number, displayid: number}, slot: number}]} equipments
* @param env {('classic'|'live')}: select game enve
* @returns {Promise<number[]>}
*/
async function findItemsInEquipments(equipments) {
async function findItemsInEquipments(equipments, env=`live`) {
for (const equipment of equipments) {
if (NOT_DISPLAYED_SLOTS.includes(equipment.slot)) {
continue
Expand All @@ -207,7 +228,8 @@ async function findItemsInEquipments(equipments) {
const displaySlot = await getDisplaySlot(
displayedItem.entry,
equipment.slot,
displayedItem.displayid
displayedItem.displayid,
env
)
equipment.displaySlot = displaySlot.displaySlot
equipment.displayId = displaySlot.displayId
Expand Down Expand Up @@ -248,5 +270,6 @@ export {
findItemsInEquipments,
getDisplaySlot,
getCharacterOptions,
characterPart
characterPart,
modelingType
}
23 changes: 20 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import {
findRaceGenderOptions,
optionsFromModel,
getDisplaySlot,
findItemsInEquipments
findItemsInEquipments,
modelingType
} from "./character_modeling.js"

import "./setup.js"
Expand All @@ -13,9 +14,10 @@ import "./setup.js"
* @param aspect {number}: Size of the character
* @param containerSelector {string}: jQuery selector on the container
* @param model {{}|{id: number, type: number}}: A json representation of a character
* @param env {('classic'|'live')}: select game enve
* @returns {Promise<WowModelViewer>}
*/
async function generateModels(aspect, containerSelector, model) {
async function generateModels(aspect, containerSelector, model, env=`live`) {
let modelOptions
let fullOptions
if (model.id && model.type) {
Expand All @@ -32,15 +34,29 @@ async function generateModels(aspect, containerSelector, model) {
)
modelOptions = optionsFromModel(model, fullOptions)
}
if(env === `classic`) {
modelOptions = {
dataEnv: `classic`,
env: `classic`,
gameDataEnv: `classic`,
hd: false,
...modelOptions
}
} else {
modelOptions = {
hd: true,
...modelOptions
}
}
const models = {
type: 2,
contentPath: window.CONTENT_PATH,
// eslint-disable-next-line no-undef
container: jQuery(containerSelector),
aspect: aspect,
hd: true,
...modelOptions
}
console.log(`Creating viewer with options`, models)

// eslint-disable-next-line no-undef
const wowModelViewer = await new WowModelViewer(models)
Expand All @@ -58,4 +74,5 @@ export {
generateModels,
getDisplaySlot,
findItemsInEquipments,
modelingType
}
1 change: 1 addition & 0 deletions tests/setup.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ describe(`WH`, () => {
expect(expect(WH.WebP.getImageExtension()).toEqual(`.webp`))
})
})

Loading

0 comments on commit 4b74f4d

Please sign in to comment.