Fix formation merging issues.

The motion parameters were calculated even without members, which caused
us to try set a undefined passclass.
Also were members added to previously merged twin-formations. Once
merged (i.e. disbanded), they are moved out of world now.

Some cleanups/deduplication whilst at it.

Reported by: @andy5995 at the forums
(https://wildfiregames.com/forum/topic/71578-feedbacks-from-a26-svn-tests/page/8/#comment-505078)
Differential revision: https://code.wildfiregames.com/D4727
Comments by: @Langbart, @marder
Tested by: @Langbart
Fixes #6580

This was SVN commit r26993.
This commit is contained in:
Freagarach
2022-06-30 06:04:05 +00:00
parent 5ab132c16c
commit d1538f7fbd
2 changed files with 30 additions and 51 deletions
@@ -380,33 +380,38 @@ Formation.prototype.SetMembers = function(ents)
Formation.prototype.RemoveMembers = function(ents, renamed = false)
{
this.offsets = undefined;
this.members = this.members.filter(ent => ents.indexOf(ent) === -1);
this.members = this.members.filter(ent => !ents.includes(ent));
for (let ent of ents)
for (const ent of ents)
{
this.finishedEntities.delete(ent);
let cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI);
const cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI);
cmpUnitAI.UpdateWorkOrders();
cmpUnitAI.SetFormationController(INVALID_ENTITY);
cmpUnitAI.UnsetFormationController();
}
for (let ent of this.formationMembersWithAura)
{
let cmpAuras = Engine.QueryInterface(ent, IID_Auras);
const cmpAuras = Engine.QueryInterface(ent, IID_Auras);
cmpAuras.RemoveFormationAura(ents);
// The unit with the aura is also removed from the formation.
if (ents.indexOf(ent) !== -1)
if (ents.includes(ent))
cmpAuras.RemoveFormationAura(this.members);
}
this.formationMembersWithAura = this.formationMembersWithAura.filter(function(e) { return ents.indexOf(e) == -1; });
this.formationMembersWithAura = this.formationMembersWithAura.filter(ent => !ents.includes(ent));
// If there's nobody left, destroy the formation
// unless this is a rename where we can have 0 members temporarily.
if (this.members.length < +this.template.RequiredMemberCount && !renamed)
if (!renamed && this.members.length < +this.template.RequiredMemberCount)
{
this.Disband();
// Hack: switch to a clean state to stop timers.
const cmpUnitAI = Engine.QueryInterface(this.entity, IID_UnitAI);
cmpUnitAI.UnitFsm.SwitchToNextState(cmpUnitAI, "");
Engine.QueryInterface(this.entity, IID_Position).MoveOutOfWorld();
this.DeleteTwinFormations();
Engine.DestroyEntity(this.entity);
return;
}
@@ -459,27 +464,7 @@ Formation.prototype.AddMembers = function(ents)
*/
Formation.prototype.Disband = function()
{
for (let ent of this.members)
{
let cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI);
cmpUnitAI.SetFormationController(INVALID_ENTITY);
}
for (let ent of this.formationMembersWithAura)
{
let cmpAuras = Engine.QueryInterface(ent, IID_Auras);
cmpAuras.RemoveFormationAura(this.members);
}
this.members = [];
this.finishedEntities.clear();
this.formationMembersWithAura = [];
this.offsets = undefined;
let cmpUnitAI = Engine.QueryInterface(this.entity, IID_UnitAI);
// Hack: switch to a clean state to stop timers.
cmpUnitAI.UnitFsm.SwitchToNextState(cmpUnitAI, "");
Engine.DestroyEntity(this.entity);
this.RemoveMembers(this.members);
};
/**
@@ -901,10 +886,13 @@ Formation.prototype.DoesAngleDifferenceAllowTurning = function(a1, a2)
*/
Formation.prototype.ComputeMotionParameters = function()
{
if (!this.members.length)
return;
let minSpeed = Infinity;
let minAcceleration = Infinity;
let maxClearance = 0;
let maxPassClass;
let maxPassClass = "default";
const cmpPathfinder = Engine.QueryInterface(SYSTEM_ENTITY, IID_Pathfinder);
for (let ent of this.members)
@@ -968,11 +956,9 @@ Formation.prototype.ShapeUpdate = function()
// Merge the members from the twin formation into this one
// twin formations should always have exactly the same orders.
let otherMembers = cmpOtherFormation.members;
const otherMembers = cmpOtherFormation.members;
cmpOtherFormation.RemoveMembers(otherMembers);
this.AddMembers(otherMembers);
Engine.DestroyEntity(this.twinFormations[i]);
this.twinFormations.splice(i, 1);
}
// Switch between column and box if necessary.
let cmpUnitAI = Engine.QueryInterface(this.entity, IID_UnitAI);
@@ -5181,24 +5181,17 @@ UnitAI.prototype.SetFormationController = function(ent)
{
this.formationController = ent;
// Set obstruction group, so we can walk through members
// of our own formation (or ourself if not in formation)
const cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction);
if (cmpObstruction)
{
if (ent == INVALID_ENTITY)
cmpObstruction.SetControlGroup(this.entity);
else
cmpObstruction.SetControlGroup(ent);
}
// Set obstruction group, so we can walk through members of our own formation.
Engine.QueryInterface(this.entity, IID_Obstruction)?.SetControlGroup(ent);
Engine.QueryInterface(this.entity, IID_UnitMotion)?.SetMemberOfFormation(ent);
};
const cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
if (cmpUnitMotion)
cmpUnitMotion.SetMemberOfFormation(ent);
// If we were removed from a formation, let the FSM switch back to INDIVIDUAL
if (ent == INVALID_ENTITY)
this.UnitFsm.ProcessMessage(this, { "type": "FormationLeave" });
UnitAI.prototype.UnsetFormationController = function()
{
this.formationController = INVALID_ENTITY;
Engine.QueryInterface(this.entity, IID_Obstruction)?.SetControlGroup(this.entity);
Engine.QueryInterface(this.entity, IID_UnitMotion)?.SetMemberOfFormation(this.formationController);
this.UnitFsm.ProcessMessage(this, { "type": "FormationLeave" });
};
UnitAI.prototype.GetFormationController = function()