diff --git a/src/MarbleWorld.hx b/src/MarbleWorld.hx index 7dbb14672..e130dc214 100644 --- a/src/MarbleWorld.hx +++ b/src/MarbleWorld.hx @@ -956,29 +956,28 @@ class MarbleWorld extends Scheduler { } public function addSimGroup(simGroup:MissionElementSimGroup) { - if (simGroup.elements.filter((element) -> element._type == MissionElementType.PathedInterior).length != 0) { + var pathedInteriorElements:Array = cast simGroup.elements.filter((element) -> element._type == MissionElementType.PathedInterior); + if (pathedInteriorElements.length != 0) { // Create the pathed interior resourceLoadFuncs.push(fwd -> { - src.PathedInterior.createFromSimGroup(simGroup, cast this, pathedInterior -> { - this.addPathedInterior(pathedInterior, () -> { - if (pathedInterior == null) { - fwd(); - Console.error("Unable to load pathed interior"); - return; - } - - // if (pathedInterior.hasCollision) - // this.physics.addInterior(pathedInterior); - for (trigger in pathedInterior.triggers) { - this.triggers.push(trigger); - this.collisionWorld.addEntity(trigger.collider); - } + src.PathedInterior.createFromSimGroup(simGroup, cast this, pathedInteriors -> { + if (pathedInteriors == null || pathedInteriors.length == 0) { fwd(); - }); + Console.error("Unable to load pathed interior"); + return; + } + + var count = pathedInteriors.length; + for (pathedInterior in pathedInteriors) { + this.addPathedInterior(pathedInterior, () -> { + count--; + if (count == 0) { + fwd(); + } + }); + } }); }); - - return; } for (element in simGroup.elements) { @@ -992,6 +991,9 @@ class MarbleWorld extends Scheduler { case MissionElementType.Item: resourceLoadFuncs.push(fwd -> this.addItem(cast element, fwd)); case MissionElementType.Trigger: + var te:MissionElementTrigger = cast element; + if (pathedInteriorElements.length != 0 && te.targettime != null) + continue; resourceLoadFuncs.push(fwd -> this.addTrigger(cast element, fwd)); case MissionElementType.TSStatic: resourceLoadFuncs.push(fwd -> this.addTSStatic(cast element, fwd)); @@ -1000,6 +1002,8 @@ class MarbleWorld extends Scheduler { this.addParticleEmitterNode(cast element); fwd(); }); + case MissionElementType.Path, MissionElementType.PathedInterior: + // Handled by createFromSimGroup default: } } diff --git a/src/PathedInterior.hx b/src/PathedInterior.hx index a7d0e2f04..524fe44e4 100644 --- a/src/PathedInterior.hx +++ b/src/PathedInterior.hx @@ -64,25 +64,61 @@ class PathedInterior extends InteriorObject { var soundChannel:Channel; - public static function createFromSimGroup(simGroup:MissionElementSimGroup, level:MarbleWorld, onFinish:PathedInterior->Void) { - var interiorElement:MissionElementPathedInterior = cast simGroup.elements.filter((element) -> element._type == MissionElementType.PathedInterior)[0]; - var difFile = level.mission.getDifPath(interiorElement.interiorresource); - if (difFile == null) - onFinish(null); - var pathedInterior = new PathedInterior(); - pathedInterior.level = level; - pathedInterior.collisionWorld = level.collisionWorld; - - DifBuilder.loadDif(difFile, pathedInterior, () -> { - pathedInterior.identifier = difFile + interiorElement.interiorindex; - - pathedInterior.simGroup = simGroup; - pathedInterior.element = interiorElement; - level.interiors.push(pathedInterior); - pathedInterior.init(level, () -> { - onFinish(pathedInterior); - }); - }, cast MisParser.parseNumber(interiorElement.interiorindex)); + public static function createFromSimGroup(simGroup:MissionElementSimGroup, level:MarbleWorld, onFinish:Array->Void) { + var interiorElements:Array = cast simGroup.elements.filter((element) -> element._type == MissionElementType.PathedInterior); + if (interiorElements.length == 0) { + onFinish([]); + return; + } + + var createdInteriors:Array = []; + var total = interiorElements.length; + var completed = 0; + + var triggers = simGroup.elements.filter((element) -> element._type == MissionElementType.Trigger); + var mustChangeTriggers:Array = []; + for (triggerElement in triggers) { + var te:MissionElementTrigger = cast triggerElement; + if (te.targettime == null) + continue; // Not a pathed interior trigger + var trigger = new MustChangeTrigger(te, level); + mustChangeTriggers.push(trigger); + level.triggers.push(trigger); + level.collisionWorld.addEntity(trigger.collider); + } + + for (interiorElement in interiorElements) { + var difFile = level.mission.getDifPath(interiorElement.interiorresource); + if (difFile == null) { + completed++; + if (completed == total) { + onFinish(createdInteriors); + } + continue; + } + var pathedInterior = new PathedInterior(); + pathedInterior.level = level; + pathedInterior.collisionWorld = level.collisionWorld; + + DifBuilder.loadDif(difFile, pathedInterior, () -> { + pathedInterior.identifier = difFile + interiorElement.interiorindex; + + pathedInterior.simGroup = simGroup; + pathedInterior.element = interiorElement; + for (mct in mustChangeTriggers) { + mct.addInterior(pathedInterior); + pathedInterior.triggers.push(mct); + } + level.interiors.push(pathedInterior); + pathedInterior.init(level, () -> { + createdInteriors.push(pathedInterior); + completed++; + if (completed == total) { + onFinish(createdInteriors); + } + }); + }, cast MisParser.parseNumber(interiorElement.interiorindex)); + } } public function new() { @@ -113,34 +149,38 @@ class PathedInterior extends InteriorObject { this.path = cast this.simGroup.elements.filter((element) -> element._type == MissionElementType.Path)[0]; - this.markerData = this.path.markers.map(x -> { - var marker = new PathedInteriorMarker(); - marker.msToNext = MisParser.parseNumber(x.mstonext) / 1000; - marker.smoothingType = switch (x.smoothingtype) { - case "Accelerate": - PathedInteriorMarker.SMOOTHING_ACCELERATE; - case "Spline": - PathedInteriorMarker.SMOOTHING_SPLINE; - default: - PathedInteriorMarker.SMOOTHING_LINEAR; - }; - marker.position = MisParser.parseVector3(x.position); - marker.position.x = -marker.position.x; - marker.rotation = MisParser.parseRotation(x.rotation); - marker.rotation.x = -marker.rotation.x; - marker.rotation.w = -marker.rotation.w; - return marker; - }); - - this.computeDuration(); - - var triggers = this.simGroup.elements.filter((element) -> element._type == MissionElementType.Trigger); - for (triggerElement in triggers) { - var te:MissionElementTrigger = cast triggerElement; - if (te.targettime == null) - continue; // Not a pathed interior trigger - var trigger = new MustChangeTrigger(te, cast this); - this.triggers.push(trigger); + if (this.path != null) { + this.markerData = this.path.markers.map(x -> { + var marker = new PathedInteriorMarker(); + marker.msToNext = MisParser.parseNumber(x.mstonext) / 1000; + marker.smoothingType = switch (x.smoothingtype) { + case "Accelerate": + PathedInteriorMarker.SMOOTHING_ACCELERATE; + case "Spline": + PathedInteriorMarker.SMOOTHING_SPLINE; + default: + PathedInteriorMarker.SMOOTHING_LINEAR; + }; + marker.position = MisParser.parseVector3(x.position); + marker.position.x = -marker.position.x; + marker.rotation = MisParser.parseRotation(x.rotation); + marker.rotation.x = -marker.rotation.x; + marker.rotation.w = -marker.rotation.w; + return marker; + }); + + this.computeDuration(); + } + + if (this.triggers.length == 0) { + var triggers = this.simGroup.elements.filter((element) -> element._type == MissionElementType.Trigger); + for (triggerElement in triggers) { + var te:MissionElementTrigger = cast triggerElement; + if (te.targettime == null) + continue; // Not a pathed interior trigger + var trigger = new MustChangeTrigger(te, cast this); + this.triggers.push(trigger); + } } if (this.element.datablock.toLowerCase() == "pathedmovingblock") { diff --git a/src/triggers/MustChangeTrigger.hx b/src/triggers/MustChangeTrigger.hx index 377b883d2..f8b4c7e3f 100644 --- a/src/triggers/MustChangeTrigger.hx +++ b/src/triggers/MustChangeTrigger.hx @@ -6,23 +6,39 @@ import src.TimeState; import mis.MisParser; class MustChangeTrigger extends Trigger { - var interior:PathedInterior; + public var interiors:Array = []; - public function new(element:MissionElementTrigger, interior:PathedInterior) { - super(element, interior.level); - this.interior = interior; + public function new(element:MissionElementTrigger, levelOrInterior:Dynamic, ?interior:PathedInterior) { + if (Std.isOfType(levelOrInterior, PathedInterior)) { + var pi:PathedInterior = cast levelOrInterior; + super(element, pi.level); + this.interiors.push(pi); + } else { + super(element, cast levelOrInterior); + } + if (interior != null && !this.interiors.contains(interior)) { + this.interiors.push(interior); + } + } + + public function addInterior(interior:PathedInterior) { + if (interior != null && !this.interiors.contains(interior)) { + this.interiors.push(interior); + } } public override function onMarbleEnter(marble:src.Marble, time:TimeState) { var ttime = MisParser.parseNumber(this.element.targettime); if (ttime > 0) ttime /= 1000; - this.interior.setTargetTime(time, ttime); - if (this.element.instant == "1") { - if (this.element.icontinuetottime != null && this.element.icontinuetottime != "0") { - // Absolutely strange, and not sure if it's even a thing in MBG, but is implement nonetheless. - this.interior.currentTime = this.interior.targetTime; - this.interior.targetTime = MisParser.parseNumber(this.element.icontinuetottime) / 1000; + for (interior in this.interiors) { + interior.setTargetTime(time, ttime); + if (this.element.instant == "1") { + if (this.element.icontinuetottime != null && this.element.icontinuetottime != "0") { + // Absolutely strange, and not sure if it's even a thing in MBG, but is implement nonetheless. + interior.currentTime = interior.targetTime; + interior.targetTime = MisParser.parseNumber(this.element.icontinuetottime) / 1000; + } } } // this.level.replay.recordMarbleEnter(this);