2019-08-26 21:42:12 +08:00
|
|
|
import { BufferGeometry, CylinderBufferGeometry, Texture } from "three";
|
2019-07-18 01:37:48 +08:00
|
|
|
import { LoadingCache } from "./LoadingCache";
|
2020-07-17 06:00:17 +08:00
|
|
|
import { Endianness } from "../../core/data_formats/block/Endianness";
|
|
|
|
import { ArrayBufferCursor } from "../../core/data_formats/block/cursor/ArrayBufferCursor";
|
2020-07-15 03:50:35 +08:00
|
|
|
import { ninja_object_to_buffer_geometry } from "../../core/rendering/conversion/ninja_geometry";
|
2020-01-18 05:42:11 +08:00
|
|
|
import { NjObject, parse_nj, parse_xj } from "../../core/data_formats/parsing/ninja";
|
2019-08-26 21:42:12 +08:00
|
|
|
import { parse_xvm } from "../../core/data_formats/parsing/ninja/texture";
|
2020-01-27 06:13:09 +08:00
|
|
|
import { xvm_to_three_textures } from "../../core/rendering/conversion/ninja_textures";
|
2019-08-26 21:42:12 +08:00
|
|
|
import { object_data, ObjectType } from "../../core/data_formats/parsing/quest/object_types";
|
|
|
|
import { NpcType } from "../../core/data_formats/parsing/quest/npc_types";
|
2019-09-22 03:47:00 +08:00
|
|
|
import {
|
|
|
|
entity_type_to_string,
|
|
|
|
EntityType,
|
|
|
|
is_npc_type,
|
2020-07-19 05:00:48 +08:00
|
|
|
} from "../../core/data_formats/parsing/quest/Quest";
|
2019-12-22 05:49:41 +08:00
|
|
|
import { HttpClient } from "../../core/HttpClient";
|
2019-12-25 07:17:02 +08:00
|
|
|
import { Disposable } from "../../core/observable/Disposable";
|
2020-09-27 06:31:22 +08:00
|
|
|
import { LogManager } from "../../core/logging";
|
2019-12-26 07:44:30 +08:00
|
|
|
import { DisposablePromise } from "../../core/DisposablePromise";
|
|
|
|
import { Disposer } from "../../core/observable/Disposer";
|
2019-12-22 05:49:41 +08:00
|
|
|
|
2019-12-25 07:17:02 +08:00
|
|
|
const logger = LogManager.get("quest_editor/loading/EntityAssetLoader");
|
2019-12-22 05:49:41 +08:00
|
|
|
|
2019-12-25 07:17:02 +08:00
|
|
|
const DEFAULT_ENTITY = new CylinderBufferGeometry(3, 3, 20);
|
|
|
|
DEFAULT_ENTITY.translate(0, 10, 0);
|
|
|
|
DEFAULT_ENTITY.computeBoundingBox();
|
|
|
|
DEFAULT_ENTITY.computeBoundingSphere();
|
|
|
|
|
2020-01-18 01:23:32 +08:00
|
|
|
const DEFAULT_ENTITY_PROMISE = DisposablePromise.resolve<BufferGeometry>(DEFAULT_ENTITY);
|
2019-12-25 07:17:02 +08:00
|
|
|
|
|
|
|
const DEFAULT_ENTITY_TEX: Texture[] = [];
|
|
|
|
|
2020-01-18 01:23:32 +08:00
|
|
|
const DEFAULT_ENTITY_TEX_PROMISE = DisposablePromise.resolve<Texture[]>(DEFAULT_ENTITY_TEX);
|
2019-12-25 07:17:02 +08:00
|
|
|
|
2020-01-18 05:42:11 +08:00
|
|
|
// TODO: load correct parts for entities that can have different geometries.
|
2019-12-25 07:17:02 +08:00
|
|
|
export class EntityAssetLoader implements Disposable {
|
2019-12-26 07:44:30 +08:00
|
|
|
private readonly disposer = new Disposer();
|
2020-09-25 01:07:22 +08:00
|
|
|
private readonly geom_cache = this.disposer.add(new LoadingCache<string, BufferGeometry>());
|
|
|
|
private readonly tex_cache = this.disposer.add(new LoadingCache<string, Texture[]>());
|
2019-12-25 07:17:02 +08:00
|
|
|
|
|
|
|
constructor(private readonly http_client: HttpClient) {
|
|
|
|
this.warm_up_caches();
|
|
|
|
}
|
|
|
|
|
|
|
|
dispose(): void {
|
2019-12-26 07:44:30 +08:00
|
|
|
this.disposer.dispose();
|
2019-12-25 07:17:02 +08:00
|
|
|
}
|
2019-12-22 05:49:41 +08:00
|
|
|
|
2020-09-25 01:07:22 +08:00
|
|
|
load_geometry(type: EntityType, model?: number): DisposablePromise<BufferGeometry> {
|
|
|
|
return this.geom_cache.get_or_set(`${type}-${model ?? ""}`, () => {
|
2020-01-18 05:42:11 +08:00
|
|
|
return DisposablePromise.all(
|
|
|
|
geometry_parts(type).map(no =>
|
2020-09-25 01:07:22 +08:00
|
|
|
this.load_data(type, AssetType.Geometry, no, model)
|
2020-01-18 05:42:11 +08:00
|
|
|
.then(({ url, data }) => {
|
|
|
|
const cursor = new ArrayBufferCursor(data, Endianness.Little);
|
|
|
|
const nj_objects = url.endsWith(".nj")
|
|
|
|
? parse_nj(cursor)
|
|
|
|
: parse_xj(cursor);
|
2019-12-26 07:44:30 +08:00
|
|
|
|
2020-01-18 05:42:11 +08:00
|
|
|
if (nj_objects.success && nj_objects.value.length) {
|
|
|
|
return nj_objects.value;
|
|
|
|
} else {
|
|
|
|
logger.warn(
|
|
|
|
`Couldn't parse ${url} for ${entity_type_to_string(type)}.`,
|
|
|
|
);
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.catch(e => {
|
|
|
|
logger.warn(
|
|
|
|
`Couldn't load geometry file for ${entity_type_to_string(type)}.`,
|
|
|
|
e,
|
|
|
|
);
|
|
|
|
return [];
|
|
|
|
}),
|
|
|
|
),
|
|
|
|
).then((nj_object_arrays: NjObject[][]) => {
|
|
|
|
const nj_objects = nj_object_arrays.flat();
|
|
|
|
const nj_object = nj_objects[0];
|
|
|
|
|
|
|
|
for (let i = 1; i < nj_objects.length; i++) {
|
|
|
|
nj_object.add_child(nj_objects[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nj_object) {
|
2020-09-25 01:07:22 +08:00
|
|
|
nj_object.evaluation_flags.break_child_trace = false;
|
2020-01-18 05:42:11 +08:00
|
|
|
return ninja_object_to_buffer_geometry(nj_object);
|
|
|
|
} else {
|
2019-12-22 05:49:41 +08:00
|
|
|
return DEFAULT_ENTITY;
|
2020-01-18 05:42:11 +08:00
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
2019-12-22 05:49:41 +08:00
|
|
|
}
|
|
|
|
|
2020-09-25 01:07:22 +08:00
|
|
|
load_textures(type: EntityType, model?: number): DisposablePromise<Texture[]> {
|
2020-10-02 00:45:05 +08:00
|
|
|
let suffix: string;
|
|
|
|
|
|
|
|
if (
|
|
|
|
type === ObjectType.FloatingRocks ||
|
|
|
|
(type === ObjectType.BigBrownRock && model == undefined)
|
|
|
|
) {
|
|
|
|
suffix = "-0";
|
|
|
|
} else {
|
|
|
|
suffix = "";
|
|
|
|
}
|
|
|
|
|
2020-09-25 01:07:22 +08:00
|
|
|
return this.tex_cache.get_or_set(`${type}-${model ?? ""}`, () =>
|
2020-10-02 00:45:05 +08:00
|
|
|
this.load_data(type, AssetType.Texture, suffix, model)
|
2019-12-26 07:44:30 +08:00
|
|
|
.then(({ data }) => {
|
|
|
|
const cursor = new ArrayBufferCursor(data, Endianness.Little);
|
|
|
|
const xvm = parse_xvm(cursor);
|
2020-01-27 06:13:09 +08:00
|
|
|
return xvm.success ? xvm_to_three_textures(xvm.value) : [];
|
2019-12-26 07:44:30 +08:00
|
|
|
})
|
|
|
|
.catch(e => {
|
2020-01-17 04:45:20 +08:00
|
|
|
logger.warn(
|
2019-12-26 07:44:30 +08:00
|
|
|
`Couldn't load texture file for ${entity_type_to_string(type)}.`,
|
|
|
|
e,
|
|
|
|
);
|
|
|
|
return DEFAULT_ENTITY_TEX;
|
|
|
|
}),
|
|
|
|
);
|
2019-12-22 05:49:41 +08:00
|
|
|
}
|
|
|
|
|
2020-01-18 01:23:32 +08:00
|
|
|
private load_data(
|
2019-12-22 05:49:41 +08:00
|
|
|
type: EntityType,
|
|
|
|
asset_type: AssetType,
|
2020-09-25 01:07:22 +08:00
|
|
|
suffix?: string,
|
|
|
|
model?: number,
|
2019-12-26 07:44:30 +08:00
|
|
|
): DisposablePromise<{ url: string; data: ArrayBuffer }> {
|
2020-09-25 01:07:22 +08:00
|
|
|
const url = entity_type_to_url(type, asset_type, suffix, model);
|
2019-12-26 07:44:30 +08:00
|
|
|
return this.http_client
|
|
|
|
.get(url)
|
|
|
|
.array_buffer()
|
|
|
|
.then(data => ({ url, data }));
|
2019-12-22 05:49:41 +08:00
|
|
|
}
|
2019-07-18 01:37:48 +08:00
|
|
|
|
2019-12-25 07:17:02 +08:00
|
|
|
/**
|
|
|
|
* Warms up the caches with default data for all entities without assets.
|
|
|
|
*/
|
|
|
|
private warm_up_caches(): void {
|
|
|
|
for (const type of [
|
|
|
|
NpcType.Unknown,
|
|
|
|
NpcType.Migium,
|
|
|
|
NpcType.Hidoom,
|
2020-10-02 00:45:05 +08:00
|
|
|
NpcType.VolOptPart1,
|
2019-12-25 07:17:02 +08:00
|
|
|
NpcType.DeathGunner,
|
|
|
|
NpcType.StRappy,
|
|
|
|
NpcType.HalloRappy,
|
|
|
|
NpcType.EggRappy,
|
|
|
|
NpcType.Migium2,
|
|
|
|
NpcType.Hidoom2,
|
|
|
|
NpcType.Recon,
|
|
|
|
|
|
|
|
ObjectType.Unknown,
|
|
|
|
ObjectType.PlayerSet,
|
|
|
|
ObjectType.Particle,
|
|
|
|
ObjectType.LightCollision,
|
|
|
|
ObjectType.EnvSound,
|
|
|
|
ObjectType.FogCollision,
|
|
|
|
ObjectType.EventCollision,
|
|
|
|
ObjectType.CharaCollision,
|
|
|
|
ObjectType.ObjRoomID,
|
|
|
|
ObjectType.LensFlare,
|
|
|
|
ObjectType.ScriptCollision,
|
|
|
|
ObjectType.MapCollision,
|
|
|
|
ObjectType.ScriptCollisionA,
|
|
|
|
ObjectType.ItemLight,
|
|
|
|
ObjectType.RadarCollision,
|
|
|
|
ObjectType.FogCollisionSW,
|
|
|
|
ObjectType.ImageBoard,
|
|
|
|
ObjectType.UnknownItem29,
|
|
|
|
ObjectType.UnknownItem30,
|
|
|
|
ObjectType.UnknownItem31,
|
|
|
|
ObjectType.MenuActivation,
|
|
|
|
ObjectType.BoxDetectObject,
|
|
|
|
ObjectType.SymbolChatObject,
|
|
|
|
ObjectType.TouchPlateObject,
|
|
|
|
ObjectType.TargetableObject,
|
|
|
|
ObjectType.EffectObject,
|
|
|
|
ObjectType.CountDownObject,
|
|
|
|
ObjectType.UnknownItem38,
|
|
|
|
ObjectType.UnknownItem39,
|
|
|
|
ObjectType.UnknownItem40,
|
|
|
|
ObjectType.UnknownItem41,
|
|
|
|
ObjectType.TelepipeLocation,
|
|
|
|
ObjectType.BGMCollision,
|
|
|
|
ObjectType.Pioneer2InvisibleTouchplate,
|
|
|
|
ObjectType.TempleMapDetect,
|
|
|
|
ObjectType.Firework,
|
|
|
|
ObjectType.MainRagolTeleporterBattleInNextArea,
|
|
|
|
ObjectType.Rainbow,
|
|
|
|
ObjectType.FloatingBlueLight,
|
|
|
|
ObjectType.PopupTrapNoTech,
|
|
|
|
ObjectType.Poison,
|
|
|
|
ObjectType.EnemyTypeBoxYellow,
|
|
|
|
ObjectType.EnemyTypeBoxBlue,
|
|
|
|
ObjectType.EmptyTypeBoxBlue,
|
|
|
|
ObjectType.FloatingSoul,
|
|
|
|
ObjectType.Butterfly,
|
|
|
|
ObjectType.UnknownItem400,
|
2020-10-01 02:07:29 +08:00
|
|
|
ObjectType.CcaAreaTeleporter,
|
2019-12-25 07:17:02 +08:00
|
|
|
ObjectType.UnknownItem523,
|
|
|
|
ObjectType.WhiteBird,
|
|
|
|
ObjectType.OrangeBird,
|
|
|
|
ObjectType.UnknownItem529,
|
|
|
|
ObjectType.UnknownItem530,
|
|
|
|
ObjectType.Seagull,
|
|
|
|
ObjectType.UnknownItem576,
|
|
|
|
ObjectType.WarpInBarbaRayRoom,
|
|
|
|
ObjectType.UnknownItem672,
|
|
|
|
ObjectType.InstaWarp,
|
|
|
|
ObjectType.LabInvisibleObject,
|
|
|
|
ObjectType.UnknownItem700,
|
2020-01-18 05:42:11 +08:00
|
|
|
ObjectType.Ep4LightSource,
|
|
|
|
ObjectType.BreakableBrownRock,
|
|
|
|
ObjectType.UnknownItem897,
|
|
|
|
ObjectType.UnknownItem898,
|
|
|
|
ObjectType.OozingDesertPlant,
|
|
|
|
ObjectType.UnknownItem901,
|
|
|
|
ObjectType.UnknownItem903,
|
|
|
|
ObjectType.UnknownItem904,
|
|
|
|
ObjectType.UnknownItem905,
|
|
|
|
ObjectType.UnknownItem906,
|
|
|
|
ObjectType.DesertPlantHasCollision,
|
|
|
|
ObjectType.UnknownItem910,
|
|
|
|
ObjectType.UnknownItem912,
|
|
|
|
ObjectType.Heat,
|
|
|
|
ObjectType.TopOfSaintMillionEgg,
|
|
|
|
ObjectType.UnknownItem961,
|
2019-12-25 07:17:02 +08:00
|
|
|
]) {
|
2020-09-25 01:07:22 +08:00
|
|
|
this.geom_cache.set(`${type}-`, DEFAULT_ENTITY_PROMISE);
|
|
|
|
this.tex_cache.set(`${type}-`, DEFAULT_ENTITY_TEX_PROMISE);
|
2019-12-25 07:17:02 +08:00
|
|
|
}
|
|
|
|
}
|
2019-07-18 01:37:48 +08:00
|
|
|
}
|
|
|
|
|
2020-09-25 01:07:22 +08:00
|
|
|
/**
|
|
|
|
* @returns the suffix of each geometry part.
|
|
|
|
*/
|
|
|
|
function geometry_parts(type: EntityType): (string | undefined)[] {
|
2020-01-18 05:42:11 +08:00
|
|
|
switch (type) {
|
|
|
|
case ObjectType.Teleporter:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2"];
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.Warp:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2"];
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.BossTeleporter:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2"];
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.QuestWarp:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2"];
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.Epilogue:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2"];
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.MainRagolTeleporter:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2"];
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.PrincipalWarp:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2"];
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.TeleporterDoor:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2"];
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.EasterEgg:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2"];
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.ValentinesHeart:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2", "-3"];
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.ChristmasTree:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2", "-3", "-4"];
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.TwentyFirstCentury:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2"];
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.WelcomeBoard:
|
2020-09-25 01:07:22 +08:00
|
|
|
return [""]; // TODO: position part 2 correctly.
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.ForestDoor:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2", "-3", "-4", "-5"];
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.ForestSwitch:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2", "-3"];
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.LaserFence:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2"];
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.LaserSquareFence:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2"];
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.ForestLaserFenceSwitch:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2", "-3"];
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.Probe:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["-0"]; // TODO: use correct part.
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.RandomTypeBox1:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["-2"]; // What are the other two parts for?
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.BlackSlidingDoor:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2"];
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.EnergyBarrier:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2"];
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.SwitchNoneDoor:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2"];
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.EnemyBoxGrey:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["-2"]; // What are the other two parts for?
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.FixedTypeBox:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["-3"]; // What are the other three parts for?
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.EnemyBoxBrown:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["-3"]; // What are the other three parts for?
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.LaserFenceEx:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2"];
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.LaserSquareFenceEx:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2"];
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.CavesSmashingPillar:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-3"]; // What's part 2 for?
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.RobotRechargeStation:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2"];
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.RuinsTeleporter:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2", "-3", "-4"];
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.RuinsWarpSiteToSite:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2"];
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.RuinsSwitch:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2"];
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.RuinsPillarTrap:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2", "-3", "-4"];
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.RuinsCrystal:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2", "-3"];
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.FloatingRocks:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["-0"];
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.ItemBoxCca:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-3"]; // What are the other two parts for?
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.TeleporterEp2:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2"];
|
2020-10-01 02:07:29 +08:00
|
|
|
case ObjectType.CcaDoor:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2"];
|
2020-10-01 02:07:29 +08:00
|
|
|
case ObjectType.SpecialBoxCca:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-4"]; // What are the other two parts for?
|
2020-10-01 02:07:29 +08:00
|
|
|
case ObjectType.BigCcaDoor:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2", "-3", "-4"];
|
2020-10-01 02:07:29 +08:00
|
|
|
case ObjectType.BigCcaDoorSwitch:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2"];
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.LaserDetect:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2"]; // TODO: use correct part.
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.LabCeilingWarp:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-2"];
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.BigBrownRock:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["-0"]; // TODO: use correct part.
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.BigBlackRocks:
|
2020-09-25 01:07:22 +08:00
|
|
|
return [""];
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.BeeHive:
|
2020-09-25 01:07:22 +08:00
|
|
|
return ["", "-0", "-1"];
|
2020-01-18 05:42:11 +08:00
|
|
|
default:
|
|
|
|
return [undefined];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-18 01:37:48 +08:00
|
|
|
enum AssetType {
|
|
|
|
Geometry,
|
|
|
|
Texture,
|
|
|
|
}
|
|
|
|
|
2020-01-18 01:23:32 +08:00
|
|
|
/**
|
|
|
|
* @param type
|
|
|
|
* @param asset_type
|
2020-09-25 01:07:22 +08:00
|
|
|
* @param suffix - Asset suffix. Some entities have multiple assets that need to be combined.
|
|
|
|
* @param model - Model variant (e.g. Sonic, Tails, Knuckles or Doctor Eggman).
|
2020-01-18 01:23:32 +08:00
|
|
|
*/
|
2020-09-25 01:07:22 +08:00
|
|
|
function entity_type_to_url(
|
|
|
|
type: EntityType,
|
|
|
|
asset_type: AssetType,
|
|
|
|
suffix?: string,
|
|
|
|
model?: number,
|
|
|
|
): string {
|
|
|
|
let full_suffix: string;
|
|
|
|
|
|
|
|
if (suffix != undefined) {
|
|
|
|
full_suffix = suffix;
|
|
|
|
} else if (model != undefined) {
|
|
|
|
full_suffix = `-${model}`;
|
|
|
|
} else {
|
|
|
|
full_suffix = "";
|
|
|
|
}
|
2020-01-18 01:23:32 +08:00
|
|
|
|
2019-09-22 03:47:00 +08:00
|
|
|
if (is_npc_type(type)) {
|
|
|
|
switch (type) {
|
|
|
|
// The dubswitch model is in XJ format.
|
|
|
|
case NpcType.Dubswitch:
|
|
|
|
return `/npcs/${NpcType[type]}.${asset_type === AssetType.Geometry ? "xj" : "xvm"}`;
|
|
|
|
|
|
|
|
// Episode II VR Temple
|
|
|
|
|
|
|
|
case NpcType.Hildebear2:
|
2020-09-25 01:07:22 +08:00
|
|
|
return entity_type_to_url(NpcType.Hildebear, asset_type, suffix, model);
|
2019-09-22 03:47:00 +08:00
|
|
|
case NpcType.Hildeblue2:
|
2020-09-25 01:07:22 +08:00
|
|
|
return entity_type_to_url(NpcType.Hildeblue, asset_type, suffix, model);
|
2019-09-22 03:47:00 +08:00
|
|
|
case NpcType.RagRappy2:
|
2020-09-25 01:07:22 +08:00
|
|
|
return entity_type_to_url(NpcType.RagRappy, asset_type, suffix, model);
|
2019-09-22 03:47:00 +08:00
|
|
|
case NpcType.Monest2:
|
2020-09-25 01:07:22 +08:00
|
|
|
return entity_type_to_url(NpcType.Monest, asset_type, suffix, model);
|
2019-09-22 03:47:00 +08:00
|
|
|
case NpcType.Mothmant2:
|
2020-09-25 01:07:22 +08:00
|
|
|
return entity_type_to_url(NpcType.Mothmant, asset_type, suffix, model);
|
2019-09-22 03:47:00 +08:00
|
|
|
case NpcType.PoisonLily2:
|
2020-09-25 01:07:22 +08:00
|
|
|
return entity_type_to_url(NpcType.PoisonLily, asset_type, suffix, model);
|
2019-09-22 03:47:00 +08:00
|
|
|
case NpcType.NarLily2:
|
2020-09-25 01:07:22 +08:00
|
|
|
return entity_type_to_url(NpcType.NarLily, asset_type, suffix, model);
|
2019-09-22 03:47:00 +08:00
|
|
|
case NpcType.GrassAssassin2:
|
2020-09-25 01:07:22 +08:00
|
|
|
return entity_type_to_url(NpcType.GrassAssassin, asset_type, suffix, model);
|
2019-09-22 03:47:00 +08:00
|
|
|
case NpcType.Dimenian2:
|
2020-09-25 01:07:22 +08:00
|
|
|
return entity_type_to_url(NpcType.Dimenian, asset_type, suffix, model);
|
2019-09-22 03:47:00 +08:00
|
|
|
case NpcType.LaDimenian2:
|
2020-09-25 01:07:22 +08:00
|
|
|
return entity_type_to_url(NpcType.LaDimenian, asset_type, suffix, model);
|
2019-09-22 03:47:00 +08:00
|
|
|
case NpcType.SoDimenian2:
|
2020-09-25 01:07:22 +08:00
|
|
|
return entity_type_to_url(NpcType.SoDimenian, asset_type, suffix, model);
|
2019-09-22 03:47:00 +08:00
|
|
|
case NpcType.DarkBelra2:
|
2020-09-25 01:07:22 +08:00
|
|
|
return entity_type_to_url(NpcType.DarkBelra, asset_type, suffix, model);
|
2019-09-22 03:47:00 +08:00
|
|
|
|
|
|
|
// Episode II VR Spaceship
|
|
|
|
|
|
|
|
case NpcType.SavageWolf2:
|
2020-09-25 01:07:22 +08:00
|
|
|
return entity_type_to_url(NpcType.SavageWolf, asset_type, suffix, model);
|
2019-09-22 03:47:00 +08:00
|
|
|
case NpcType.BarbarousWolf2:
|
2020-09-25 01:07:22 +08:00
|
|
|
return entity_type_to_url(NpcType.BarbarousWolf, asset_type, suffix, model);
|
2019-09-22 03:47:00 +08:00
|
|
|
case NpcType.PanArms2:
|
2020-09-25 01:07:22 +08:00
|
|
|
return entity_type_to_url(NpcType.PanArms, asset_type, suffix, model);
|
2019-09-22 03:47:00 +08:00
|
|
|
case NpcType.Dubchic2:
|
2020-09-25 01:07:22 +08:00
|
|
|
return entity_type_to_url(NpcType.Dubchic, asset_type, suffix, model);
|
2019-09-22 03:47:00 +08:00
|
|
|
case NpcType.Gilchic2:
|
2020-09-25 01:07:22 +08:00
|
|
|
return entity_type_to_url(NpcType.Gilchic, asset_type, suffix, model);
|
2019-09-22 03:47:00 +08:00
|
|
|
case NpcType.Garanz2:
|
2020-09-25 01:07:22 +08:00
|
|
|
return entity_type_to_url(NpcType.Garanz, asset_type, suffix, model);
|
2019-09-22 03:47:00 +08:00
|
|
|
case NpcType.Dubswitch2:
|
2020-09-25 01:07:22 +08:00
|
|
|
return entity_type_to_url(NpcType.Dubswitch, asset_type, suffix, model);
|
2019-09-22 03:47:00 +08:00
|
|
|
case NpcType.Delsaber2:
|
2020-09-25 01:07:22 +08:00
|
|
|
return entity_type_to_url(NpcType.Delsaber, asset_type, suffix, model);
|
2019-09-22 03:47:00 +08:00
|
|
|
case NpcType.ChaosSorcerer2:
|
2020-09-25 01:07:22 +08:00
|
|
|
return entity_type_to_url(NpcType.ChaosSorcerer, asset_type, suffix, model);
|
2019-07-18 01:37:48 +08:00
|
|
|
|
|
|
|
default:
|
2020-09-25 01:07:22 +08:00
|
|
|
return `/npcs/${NpcType[type]}${full_suffix}.${
|
2020-01-18 01:23:32 +08:00
|
|
|
asset_type === AssetType.Geometry ? "nj" : "xvm"
|
|
|
|
}`;
|
2019-07-18 01:37:48 +08:00
|
|
|
}
|
|
|
|
} else {
|
2019-09-22 03:47:00 +08:00
|
|
|
if (asset_type === AssetType.Geometry) {
|
|
|
|
switch (type) {
|
|
|
|
case ObjectType.EasterEgg:
|
|
|
|
case ObjectType.ChristmasTree:
|
|
|
|
case ObjectType.ChristmasWreath:
|
|
|
|
case ObjectType.TwentyFirstCentury:
|
|
|
|
case ObjectType.Sonic:
|
|
|
|
case ObjectType.WelcomeBoard:
|
2019-09-22 22:14:38 +08:00
|
|
|
case ObjectType.FloatingJellyfish:
|
2019-09-22 03:47:00 +08:00
|
|
|
case ObjectType.RuinsSeal:
|
|
|
|
case ObjectType.Dolphin:
|
2020-01-18 05:42:11 +08:00
|
|
|
case ObjectType.Cactus:
|
2019-09-22 03:47:00 +08:00
|
|
|
case ObjectType.BigBrownRock:
|
|
|
|
case ObjectType.PoisonPlant:
|
|
|
|
case ObjectType.BigBlackRocks:
|
|
|
|
case ObjectType.FallingRock:
|
|
|
|
case ObjectType.DesertFixedTypeBoxBreakableCrystals:
|
|
|
|
case ObjectType.BeeHive:
|
2020-09-25 01:07:22 +08:00
|
|
|
return `/objects/${object_data(type).type_id}${full_suffix}.nj`;
|
2019-09-22 03:47:00 +08:00
|
|
|
|
|
|
|
default:
|
2020-09-25 01:07:22 +08:00
|
|
|
return `/objects/${object_data(type).type_id}${full_suffix}.xj`;
|
2019-09-22 03:47:00 +08:00
|
|
|
}
|
|
|
|
} else {
|
2020-09-25 01:07:22 +08:00
|
|
|
return `/objects/${object_data(type).type_id}${full_suffix}.xvm`;
|
2019-09-22 03:47:00 +08:00
|
|
|
}
|
2019-07-18 01:37:48 +08:00
|
|
|
}
|
|
|
|
}
|