Update Healer Man server

This commit is contained in:
phenom committed 2026-09-25 18:46:09 -04:00
1 parent a868401ebc
commit 48a678dcc5
295 files changed
+7644 -467

No files matched your search

@@ -101,7 +101,29 @@ const URGENT_RUNE_TEXTURE = "texture/fx/skill/rune.dds";
const URGENT_DECAL_TEXTURE = "texture/fx/skill/kan_rune_circle.dds";
function normalizedEventString(controller) {
return controller.eventString?.replaceAll("\\", "/").toLowerCase();
return controller.eventString?.replaceAll("\\", "/").replace(/^\/+/, "").toLowerCase();
}
// RuneWaker's event manager routes these callbacks outside the particle
// renderer. IDs 25 (effect trigger) and 33 (projectile flight) affect visuals
// and intentionally remain blocked until their behavior is implemented.
function visualOnlySourceTrigger(controller) {
if (controller.type !== "unsupported" || controller.sourceType !== "CRuController_EventTrigger"
|| typeof controller.anchor !== "string" || !Number.isFinite(controller.startTime)
|| controller.startTime < 0 || !Number.isFinite(controller.eventDuration)
|| controller.eventDuration < 0 || !Number.isInteger(controller.eventParameter0)
|| !Number.isInteger(controller.eventParameter1)) return false;
const eventString = normalizedEventString(controller);
if ([1, 50, 61].includes(controller.eventID)) {
return controller.eventParameter0 === 0 && controller.eventParameter1 === 0 && eventString === "";
}
if ([41, 43].includes(controller.eventID)) {
return [0, 1].includes(controller.eventParameter0)
&& /^sound\/fx\/[\w./ -]+\.(?:mp3|wav|ogg)$/.test(eventString)
&& !eventString.includes("..");
}
return controller.eventID === 44 && controller.eventParameter0 === 1
&& controller.eventParameter1 === 0 && eventString === "missile";
}
function visualOnlyHolyCastTrigger(model, motion, controller) {
@@ -163,9 +185,15 @@ function verifiedGlobalAlpha(model, motion, controller) {
&& controller.alphaTrack[0].value === 0 && controller.alphaTrack[1].value === 1
&& controller.alphaTrack[2].value === 1 && controller.alphaTrack[3].value === 0;
}
return model === RIPTIDE_IMPACT_MODEL && motion.name === "explode"
&& controller.duration === 0 && controller.alphaTrack.length === 1
&& controller.alphaTrack[0].time === 0 && controller.alphaTrack[0].value === 1;
if (model === RIPTIDE_IMPACT_MODEL && motion.name === "explode") {
return controller.duration === 0 && controller.alphaTrack.length === 1
&& controller.alphaTrack[0].time === 0 && controller.alphaTrack[0].value === 1;
}
const alphas = motion.controllers.filter((candidate) => candidate.type === "global-alpha");
const sprites = motion.controllers.filter((candidate) => candidate.type === "sprite");
return alphas.length === 1 && sprites.length > 0
&& sprites.every((sprite) => controller.anchor === ""
|| sprite.anchor.startsWith(`${controller.anchor}/`));
}
const expectedSpecialControllerCounts = new Map([
@@ -339,8 +367,7 @@ try {
delete controller.orientToTravel;
delete controller.billboardType;
}
if (controller.type === "global-alpha"
&& ![ICE_CAST_MODEL, RIPTIDE_IMPACT_MODEL, URGENT_IMPACT_MODEL].includes(model)) {
if (controller.type === "global-alpha" && !verifiedGlobalAlpha(model, motion, controller)) {
controller.type = "unsupported";
delete controller.startTime;
delete controller.duration;
@@ -370,6 +397,18 @@ try {
}
}
if (result.spriteControllers === 0) result.errors.push("No sprite controllers decoded");
for (const motion of decoded.motions) for (const controller of motion.controllers) {
if (controller.type === "emitter" && (controller.particlePath !== ""
|| controller.emitterPath !== "" || controller.tracks?.length !== 27
|| ![0, 1, 4, 5].includes(controller.tracks?.[1]?.[0]?.value))) {
result.unsupported.push("RuneWaker browser emitter geometry mode");
}
if (controller.type === "sprite" && (controller.shader !== "ruSHADER_PARTICLE_SPRITEEX"
|| ![0, 1, 2].includes(controller.blendMode)
|| ![1, 2].includes(controller.billboardType) || controller.tracks?.length !== 4)) {
result.unsupported.push("RuneWaker browser sprite mode");
}
}
result.unsupported.push(...decoded.unsupported.filter((type) => !(
model === URGENT_IMPACT_MODEL && type === "CRuEntity_Particle_Visualizer_Entity" && runeMesh
)));
@@ -384,19 +423,20 @@ try {
.filter((controller) => controller.type === "global-alpha")
.map((controller) => ({ motion, controller })));
const [expectedTriggers, expectedAlpha] = expectedSpecialControllerCounts.get(model) ?? [0, 0];
const visualOnlyControllers = unsupportedControllers.length === expectedTriggers
&& globalAlphaControllers.length === expectedAlpha
const visualOnlyControllers = (expectedTriggers === 0 || unsupportedControllers.length === expectedTriggers)
&& (expectedAlpha === 0 || globalAlphaControllers.length === expectedAlpha)
&& unsupportedControllers.every(({ motion, controller }) => (
visualOnlyHolyCastTrigger(model, motion, controller)
|| visualOnlyRisingTideTrigger(model, motion, controller)
|| visualOnlySourceTrigger(controller)
))
&& globalAlphaControllers.every(({ motion, controller }) => (
verifiedGlobalAlpha(model, motion, controller)
))
&& result.unsupported.every((type) => type === "CRuController_EventTrigger");
result.rendererReady = verifiedRuneWakerParticleModels.has(model)
&& result.errors.length === 0
&& visualOnlyControllers;
result.rendererReady = result.spriteControllers > 0
&& result.errors.length === 0 && decoded.unsupported.length === 0
&& !runeMesh && visualOnlyControllers;
result.partialRendererReady = verifiedRuneWakerParticleModels.has(model)
&& result.errors.length === 0
&& verifiedUrgentPartial(model, decoded, result, unsupportedControllers, globalAlphaControllers, runeMesh);