forked from phenom/healer-man
Release Healer Man 0.1.21
This commit is contained in:
1 parent
699fc858c9
commit
f6f2375145
210 files changed
+976039
-6247
No files matched your search
@@ -0,0 +1,95 @@
|
||||
import { CuboidCollider, RigidBody } from "@react-three/rapier";
|
||||
import { useMemo, useSyncExternalStore } from "react";
|
||||
import type { Object3D } from "three";
|
||||
import {
|
||||
activeDungeonEncounterRevision,
|
||||
subscribeDungeonEncounterSnapshots,
|
||||
} from "../game/dungeonEncounterRuntime";
|
||||
import { activeDungeonWorldObjectStates } from "../game/dungeonWorldInteraction";
|
||||
import {
|
||||
dungeonWorldObjectState,
|
||||
type DungeonWorldObjectDefinition,
|
||||
} from "../game/dungeonWorldObjects";
|
||||
import {
|
||||
DUNGEON_PHYSICAL_COLLISION_GROUPS,
|
||||
DUNGEON_SIGHT_BLOCKER_COLLISION_GROUPS,
|
||||
} from "./dungeonLineOfSight";
|
||||
import { useGameGLTF } from "./useGameGLTF";
|
||||
|
||||
function AssetObject({ definition }: { readonly definition: DungeonWorldObjectDefinition }) {
|
||||
const gltf = useGameGLTF(definition.visual!.assetUrl!);
|
||||
const visual = useMemo<Object3D>(() => gltf.scene.clone(true), [gltf.scene]);
|
||||
return <primitive object={visual} scale={definition.visual?.scale ?? [1, 1, 1]} />;
|
||||
}
|
||||
|
||||
function ProceduralObject({ definition }: { readonly definition: DungeonWorldObjectDefinition }) {
|
||||
const [x, y, z] = definition.halfExtents;
|
||||
return (
|
||||
<mesh castShadow receiveShadow>
|
||||
<boxGeometry args={[x * 2, y * 2, z * 2]} />
|
||||
<meshStandardMaterial
|
||||
color={definition.visual?.color ?? (definition.kind === "switch" ? "#dca24a" : "#65584b")}
|
||||
emissive={definition.visual?.emissive ?? "#000000"}
|
||||
roughness={0.72}
|
||||
/>
|
||||
</mesh>
|
||||
);
|
||||
}
|
||||
|
||||
function WorldObject({
|
||||
definition,
|
||||
stateId,
|
||||
}: {
|
||||
readonly definition: DungeonWorldObjectDefinition;
|
||||
readonly stateId?: string;
|
||||
}) {
|
||||
const state = dungeonWorldObjectState(definition, stateId);
|
||||
if (!state.visible) return null;
|
||||
return (
|
||||
<RigidBody
|
||||
key={`${definition.id}:${state.id}`}
|
||||
type="fixed"
|
||||
colliders={false}
|
||||
position={definition.position}
|
||||
rotation={[0, definition.yaw ?? 0, 0]}
|
||||
name={`dungeon-object:${definition.id}:${state.id}`}
|
||||
>
|
||||
{state.blocksMovement && (
|
||||
<CuboidCollider
|
||||
args={[...definition.halfExtents]}
|
||||
collisionGroups={DUNGEON_PHYSICAL_COLLISION_GROUPS}
|
||||
/>
|
||||
)}
|
||||
{state.blocksSight && (
|
||||
<CuboidCollider
|
||||
args={[...definition.halfExtents]}
|
||||
collisionGroups={DUNGEON_SIGHT_BLOCKER_COLLISION_GROUPS}
|
||||
sensor
|
||||
/>
|
||||
)}
|
||||
{definition.visual?.assetUrl
|
||||
? <AssetObject definition={definition} />
|
||||
: <ProceduralObject definition={definition} />}
|
||||
</RigidBody>
|
||||
);
|
||||
}
|
||||
|
||||
export function DungeonWorldObjects({
|
||||
definitions,
|
||||
}: {
|
||||
readonly definitions: readonly DungeonWorldObjectDefinition[];
|
||||
}) {
|
||||
useSyncExternalStore(
|
||||
subscribeDungeonEncounterSnapshots,
|
||||
activeDungeonEncounterRevision,
|
||||
activeDungeonEncounterRevision,
|
||||
);
|
||||
const states = activeDungeonWorldObjectStates();
|
||||
return (
|
||||
<group name="dungeon-world-objects">
|
||||
{definitions.map((definition) => (
|
||||
<WorldObject key={definition.id} definition={definition} stateId={states[definition.id]} />
|
||||
))}
|
||||
</group>
|
||||
);
|
||||
}
|
||||
+27
-5
@@ -4,6 +4,7 @@ import {
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
useSyncExternalStore,
|
||||
type PointerEvent as ReactPointerEvent,
|
||||
} from "react";
|
||||
import { Canvas } from "@react-three/fiber";
|
||||
@@ -52,6 +53,13 @@ import { numericFrameRateLimit } from "../game/frameRateSettings";
|
||||
import { useDocumentVisibility } from "../platform/useDocumentVisibility";
|
||||
import { CappedFrameLoop } from "./CappedFrameLoop";
|
||||
import { selectDungeonSessionPopulation } from "../game/dungeonSpawnSelection";
|
||||
import { DungeonWorldObjects } from "./DungeonWorldObjects";
|
||||
import {
|
||||
activeDungeonEncounterRevision,
|
||||
activeDungeonEncounterSpawnGroupIds,
|
||||
subscribeDungeonEncounterSnapshots,
|
||||
} from "../game/dungeonEncounterRuntime";
|
||||
import { activeEncounterSpawnGroupSpawns } from "../game/dungeonEncounterSpawns";
|
||||
|
||||
export function GameScene() {
|
||||
const activeDungeonId = useGameStore((state) => state.activeDungeonId);
|
||||
@@ -60,6 +68,11 @@ export function GameScene() {
|
||||
const manastormEncounter = useManastormStore((state) => state.currentEncounter);
|
||||
const manastormPhase = useManastormStore((state) => state.phase);
|
||||
const wailingPhase = useWailingEncounterStore((state) => state.phase);
|
||||
useSyncExternalStore(
|
||||
subscribeDungeonEncounterSnapshots,
|
||||
activeDungeonEncounterRevision,
|
||||
activeDungeonEncounterRevision,
|
||||
);
|
||||
const dungeon = requireDungeonDefinition(activeDungeonId);
|
||||
const cameraFar = Math.max(
|
||||
950,
|
||||
@@ -103,7 +116,17 @@ export function GameScene() {
|
||||
phasedStaticSpawns,
|
||||
difficultyRoamingPacks,
|
||||
);
|
||||
const staticSpawns = sessionPopulation.staticSpawns;
|
||||
const activeSpawnGroupIds = activeDungeonEncounterSpawnGroupIds();
|
||||
const encounterSpawns = activeEncounterSpawnGroupSpawns(
|
||||
dungeon.encounterSpawnGroups ?? [],
|
||||
activeSpawnGroupIds,
|
||||
difficultyMask,
|
||||
sessionPopulation.staticSpawns,
|
||||
);
|
||||
const staticSpawns = [
|
||||
...sessionPopulation.staticSpawns,
|
||||
...encounterSpawns,
|
||||
];
|
||||
const roamingPacks = sessionPopulation.roamingPacks;
|
||||
const paused = useGameStore((state) => state.paused);
|
||||
const mapOpen = useGameStore((state) => state.mapOpen);
|
||||
@@ -180,10 +203,6 @@ export function GameScene() {
|
||||
};
|
||||
}, [canvasRevision]);
|
||||
|
||||
useEffect(() => {
|
||||
useWailingEncounterStore.getState().reset();
|
||||
}, [activeDungeonId, gameMode, sessionRevision]);
|
||||
|
||||
useEffect(() => {
|
||||
setAdaptiveDpr(1.5);
|
||||
}, [activeDungeonId, sessionRevision]);
|
||||
@@ -294,6 +313,9 @@ export function GameScene() {
|
||||
<OnlinePlayerPopulation active={!simulationBlocked} />
|
||||
<PartyPopulation active={!simulationBlocked} simulate={!sharedOnline || onlineAuthority} />
|
||||
<GroundEffectTelegraphs />
|
||||
{gameMode === "dungeon" && (
|
||||
<DungeonWorldObjects definitions={dungeon.serverGameObjects} />
|
||||
)}
|
||||
<MobPopulation
|
||||
active={!simulationBlocked}
|
||||
entities={stagePopulation.entities}
|
||||
|
||||
@@ -870,7 +870,7 @@ function ProxyMob({
|
||||
level: gameMode === "manastorm"
|
||||
? definition.combat?.level
|
||||
: scaledDungeonEnemyLevel(characterLevel, boss),
|
||||
hasLoot: definition.hasLoot ?? (boss && bossHasLoot(definition.id)),
|
||||
hasLoot: Boolean((boss && bossHasLoot(definition.id)) || definition.hasLoot),
|
||||
lootSourceId: boss ? definition.id : undefined,
|
||||
healthMultiplier: baseHealthMultiplier * (manastormModifiers?.enemyStatMultiplier ?? 1),
|
||||
damageMultiplier: baseDamageMultiplier * (manastormModifiers?.enemyStatMultiplier ?? 1),
|
||||
|
||||
@@ -120,6 +120,7 @@ function PlayerController({
|
||||
const mapOpen = useGameStore((state) => state.mapOpen);
|
||||
const companionOpen = useGameStore((state) => state.companionOpen);
|
||||
const resetRevision = useGameStore((state) => state.resetRevision);
|
||||
const relocationRevision = useGameStore((state) => state.relocationRevision);
|
||||
const reportAccumulator = useRef(0);
|
||||
const activeDungeonId = useGameStore((state) => state.activeDungeonId);
|
||||
const gameMode = useGameStore((state) => state.gameMode);
|
||||
@@ -159,7 +160,7 @@ function PlayerController({
|
||||
verticalPresentationTimingRef.current = createCharacterVerticalPresentationTiming();
|
||||
verticalVelocityRef.current = 0;
|
||||
verticalMotionRef.current = "grounded";
|
||||
}, [bodyRef, orbitRef, resetRevision, spawn, verticalMotionRef]);
|
||||
}, [bodyRef, orbitRef, relocationRevision, resetRevision, spawn, verticalMotionRef]);
|
||||
|
||||
useFrame((_, delta) => {
|
||||
const body = bodyRef.current;
|
||||
|
||||
Reference in new issue
Block a user