mirror of
https://github.com/DaanVandenBosch/phantasmal-world.git
synced 2025-04-04 22:58:29 +08:00
Object models are now loaded completely.
This commit is contained in:
parent
603c221365
commit
a92dbcc287
@ -258,7 +258,7 @@ export enum ObjectType {
|
||||
UnknownItem700,
|
||||
LabCeilingWarp,
|
||||
Ep4LightSource,
|
||||
Cacti,
|
||||
Cactus,
|
||||
BigBrownRock,
|
||||
BreakableBrownRock,
|
||||
UnknownItem832,
|
||||
@ -816,7 +816,7 @@ export function pso_id_to_object_type(psoId: number): ObjectType {
|
||||
case 768:
|
||||
return ObjectType.Ep4LightSource;
|
||||
case 769:
|
||||
return ObjectType.Cacti;
|
||||
return ObjectType.Cactus;
|
||||
case 770:
|
||||
return ObjectType.BigBrownRock;
|
||||
case 771:
|
||||
@ -1798,7 +1798,7 @@ define_object_type_data(ObjectType.LabCeilingWarp, 701, "Lab Ceiling Warp", [[Ep
|
||||
define_object_type_data(ObjectType.Ep4LightSource, 768, "Ep4 Light Source", [
|
||||
[Episode.IV, [1, 2, 3, 4, 5, 6, 7, 8, 9]],
|
||||
]);
|
||||
define_object_type_data(ObjectType.Cacti, 769, "cacti", [[Episode.IV, [1, 2, 3, 4, 5, 6, 7, 8]]]);
|
||||
define_object_type_data(ObjectType.Cactus, 769, "Cactus", [[Episode.IV, [1, 2, 3, 4, 5, 6, 7, 8]]]);
|
||||
define_object_type_data(ObjectType.BigBrownRock, 770, "Big Brown Rock", [
|
||||
[Episode.IV, [1, 2, 3, 4, 5, 6, 7, 8]],
|
||||
]);
|
||||
|
@ -3,7 +3,7 @@ import { LoadingCache } from "./LoadingCache";
|
||||
import { Endianness } from "../../core/data_formats/Endianness";
|
||||
import { ArrayBufferCursor } from "../../core/data_formats/cursor/ArrayBufferCursor";
|
||||
import { ninja_object_to_buffer_geometry } from "../../core/rendering/conversion/ninja_geometry";
|
||||
import { parse_nj, parse_xj } from "../../core/data_formats/parsing/ninja";
|
||||
import { NjObject, parse_nj, parse_xj } from "../../core/data_formats/parsing/ninja";
|
||||
import { parse_xvm } from "../../core/data_formats/parsing/ninja/texture";
|
||||
import { xvm_to_textures } from "../../core/rendering/conversion/ninja_textures";
|
||||
import { object_data, ObjectType } from "../../core/data_formats/parsing/quest/object_types";
|
||||
@ -32,6 +32,7 @@ const DEFAULT_ENTITY_TEX: Texture[] = [];
|
||||
|
||||
const DEFAULT_ENTITY_TEX_PROMISE = DisposablePromise.resolve<Texture[]>(DEFAULT_ENTITY_TEX);
|
||||
|
||||
// TODO: load correct parts for entities that can have different geometries.
|
||||
export class EntityAssetLoader implements Disposable {
|
||||
private readonly disposer = new Disposer();
|
||||
private readonly geom_cache = this.disposer.add(new LoadingCache<EntityType, BufferGeometry>());
|
||||
@ -46,32 +47,54 @@ export class EntityAssetLoader implements Disposable {
|
||||
}
|
||||
|
||||
load_geometry(type: EntityType): DisposablePromise<BufferGeometry> {
|
||||
return this.geom_cache.get_or_set(type, () =>
|
||||
this.load_data(type, AssetType.Geometry)
|
||||
.then(({ url, data }) => {
|
||||
const cursor = new ArrayBufferCursor(data, Endianness.Little);
|
||||
const nj_objects = url.endsWith(".nj") ? parse_nj(cursor) : parse_xj(cursor);
|
||||
return this.geom_cache.get_or_set(type, () => {
|
||||
return DisposablePromise.all(
|
||||
geometry_parts(type).map(no =>
|
||||
this.load_data(type, AssetType.Geometry, no)
|
||||
.then(({ url, data }) => {
|
||||
const cursor = new ArrayBufferCursor(data, Endianness.Little);
|
||||
const nj_objects = url.endsWith(".nj")
|
||||
? parse_nj(cursor)
|
||||
: parse_xj(cursor);
|
||||
|
||||
if (nj_objects.success && nj_objects.value.length) {
|
||||
return ninja_object_to_buffer_geometry(nj_objects.value[0]);
|
||||
} else {
|
||||
logger.warn(`Couldn't parse ${url} for ${entity_type_to_string(type)}.`);
|
||||
return DEFAULT_ENTITY;
|
||||
}
|
||||
})
|
||||
.catch(e => {
|
||||
logger.warn(
|
||||
`Couldn't load geometry file for ${entity_type_to_string(type)}.`,
|
||||
e,
|
||||
);
|
||||
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.evaluation_flags.break_child_trace = false;
|
||||
nj_object.add_child(nj_objects[i]);
|
||||
}
|
||||
|
||||
if (nj_object) {
|
||||
return ninja_object_to_buffer_geometry(nj_object);
|
||||
} else {
|
||||
return DEFAULT_ENTITY;
|
||||
}),
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
load_textures(type: EntityType): DisposablePromise<Texture[]> {
|
||||
return this.tex_cache.get_or_set(type, () =>
|
||||
this.load_data(type, AssetType.Texture)
|
||||
this.load_data(type, AssetType.Texture, texture_part(type))
|
||||
.then(({ data }) => {
|
||||
const cursor = new ArrayBufferCursor(data, Endianness.Little);
|
||||
const xvm = parse_xvm(cursor);
|
||||
@ -90,8 +113,9 @@ export class EntityAssetLoader implements Disposable {
|
||||
private load_data(
|
||||
type: EntityType,
|
||||
asset_type: AssetType,
|
||||
no?: number,
|
||||
): DisposablePromise<{ url: string; data: ArrayBuffer }> {
|
||||
const url = entity_type_to_url(type, asset_type);
|
||||
const url = entity_type_to_url(type, asset_type, no);
|
||||
return this.http_client
|
||||
.get(url)
|
||||
.array_buffer()
|
||||
@ -158,7 +182,6 @@ export class EntityAssetLoader implements Disposable {
|
||||
ObjectType.EnemyTypeBoxYellow,
|
||||
ObjectType.EnemyTypeBoxBlue,
|
||||
ObjectType.EmptyTypeBoxBlue,
|
||||
ObjectType.FloatingRocks,
|
||||
ObjectType.FloatingSoul,
|
||||
ObjectType.Butterfly,
|
||||
ObjectType.UnknownItem400,
|
||||
@ -175,6 +198,22 @@ export class EntityAssetLoader implements Disposable {
|
||||
ObjectType.InstaWarp,
|
||||
ObjectType.LabInvisibleObject,
|
||||
ObjectType.UnknownItem700,
|
||||
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,
|
||||
]) {
|
||||
this.geom_cache.set(type, DEFAULT_ENTITY_PROMISE);
|
||||
this.tex_cache.set(type, DEFAULT_ENTITY_TEX_PROMISE);
|
||||
@ -182,6 +221,122 @@ export class EntityAssetLoader implements Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
function geometry_parts(type: EntityType): (number | undefined)[] {
|
||||
switch (type) {
|
||||
case ObjectType.Teleporter:
|
||||
return [undefined, 2];
|
||||
case ObjectType.Warp:
|
||||
return [undefined, 2];
|
||||
case ObjectType.BossTeleporter:
|
||||
return [undefined, 2];
|
||||
case ObjectType.QuestWarp:
|
||||
return [undefined, 2];
|
||||
case ObjectType.Epilogue:
|
||||
return [undefined, 2];
|
||||
case ObjectType.MainRagolTeleporter:
|
||||
return [undefined, 2];
|
||||
case ObjectType.PrincipalWarp:
|
||||
return [undefined, 2];
|
||||
case ObjectType.TeleporterDoor:
|
||||
return [undefined, 2];
|
||||
case ObjectType.EasterEgg:
|
||||
return [undefined, 2];
|
||||
case ObjectType.ValentinesHeart:
|
||||
return [undefined, 2, 3];
|
||||
case ObjectType.ChristmasTree:
|
||||
return [undefined, 2, 3, 4];
|
||||
case ObjectType.TwentyFirstCentury:
|
||||
return [undefined, 2];
|
||||
case ObjectType.WelcomeBoard:
|
||||
return [undefined]; // TODO: position part 2 correctly.
|
||||
case ObjectType.ForestDoor:
|
||||
return [undefined, 2, 3, 4, 5];
|
||||
case ObjectType.ForestSwitch:
|
||||
return [undefined, 2, 3];
|
||||
case ObjectType.LaserFence:
|
||||
return [undefined, 2];
|
||||
case ObjectType.LaserSquareFence:
|
||||
return [undefined, 2];
|
||||
case ObjectType.ForestLaserFenceSwitch:
|
||||
return [undefined, 2, 3];
|
||||
case ObjectType.Probe:
|
||||
return [0]; // TODO: use correct part.
|
||||
case ObjectType.RandomTypeBox1:
|
||||
return [undefined, 2, 3];
|
||||
case ObjectType.BlackSlidingDoor:
|
||||
return [undefined, 2];
|
||||
case ObjectType.EnergyBarrier:
|
||||
return [undefined, 2];
|
||||
case ObjectType.SwitchNoneDoor:
|
||||
return [undefined, 2];
|
||||
case ObjectType.EnemyBoxGrey:
|
||||
return [undefined, 2, 3];
|
||||
case ObjectType.FixedTypeBox:
|
||||
return [undefined, 2, 3, 4];
|
||||
case ObjectType.EnemyBoxBrown:
|
||||
return [undefined, 2, 3, 4];
|
||||
case ObjectType.LaserFenceEx:
|
||||
return [undefined, 2];
|
||||
case ObjectType.LaserSquareFenceEx:
|
||||
return [undefined, 2];
|
||||
case ObjectType.CavesSmashingPillar:
|
||||
return [undefined, 3]; // What's part 2 for?
|
||||
case ObjectType.RobotRechargeStation:
|
||||
return [undefined, 2];
|
||||
case ObjectType.RuinsTeleporter:
|
||||
return [undefined, 2, 3, 4];
|
||||
case ObjectType.RuinsWarpSiteToSite:
|
||||
return [undefined, 2];
|
||||
case ObjectType.RuinsSwitch:
|
||||
return [undefined, 2];
|
||||
case ObjectType.RuinsPillarTrap:
|
||||
return [undefined, 2, 3, 4];
|
||||
case ObjectType.RuinsCrystal:
|
||||
return [undefined, 2, 3];
|
||||
case ObjectType.FixedBoxTypeRuins:
|
||||
return [undefined, 2, 3];
|
||||
case ObjectType.RandomBoxTypeRuins:
|
||||
return [undefined, 2, 3];
|
||||
case ObjectType.FloatingRocks:
|
||||
return [0];
|
||||
case ObjectType.ItemBoxCca:
|
||||
return [undefined, 2, 3, 4];
|
||||
case ObjectType.TeleporterEp2:
|
||||
return [undefined, 2];
|
||||
case ObjectType.CCADoor:
|
||||
return [undefined, 2];
|
||||
case ObjectType.SpecialBoxCCA:
|
||||
return [undefined, 2, 3, 4];
|
||||
case ObjectType.BigCCADoor:
|
||||
return [undefined, 2, 3, 4];
|
||||
case ObjectType.BigCCADoorSwitch:
|
||||
return [undefined, 2];
|
||||
case ObjectType.LaserDetect:
|
||||
return [undefined, 2]; // TODO: use correct part.
|
||||
case ObjectType.LabCeilingWarp:
|
||||
return [undefined, 2];
|
||||
case ObjectType.BigBrownRock:
|
||||
return [0]; // TODO: use correct part.
|
||||
case ObjectType.BigBlackRocks:
|
||||
return [undefined];
|
||||
case ObjectType.BeeHive:
|
||||
return [undefined, 0, 1];
|
||||
default:
|
||||
return [undefined];
|
||||
}
|
||||
}
|
||||
|
||||
function texture_part(type: EntityType): number | undefined {
|
||||
switch (type) {
|
||||
case ObjectType.FloatingRocks:
|
||||
return 0; // TODO: use correct part.
|
||||
case ObjectType.BigBrownRock:
|
||||
return 0; // TODO: use correct part.
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
enum AssetType {
|
||||
Geometry,
|
||||
Texture,
|
||||
@ -266,7 +421,7 @@ function entity_type_to_url(type: EntityType, asset_type: AssetType, no?: number
|
||||
case ObjectType.FloatingJellyfish:
|
||||
case ObjectType.RuinsSeal:
|
||||
case ObjectType.Dolphin:
|
||||
case ObjectType.Cacti:
|
||||
case ObjectType.Cactus:
|
||||
case ObjectType.BigBrownRock:
|
||||
case ObjectType.PoisonPlant:
|
||||
case ObjectType.BigBlackRocks:
|
||||
|
Loading…
Reference in New Issue
Block a user