Skip to content

Commit c55e828

Browse files
committed
filter defense eligibility and speed up condition hinges on all defending factions being able to defend all planets
1 parent 7b64992 commit c55e828

1 file changed

Lines changed: 111 additions & 36 deletions

File tree

ZkLobbyServer/SpringieInterface/PlanetWarsMatchMaker.cs

Lines changed: 111 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -146,26 +146,9 @@ private async void TimerOnElapsed(object sender, ElapsedEventArgs elapsedEventAr
146146
break;
147147

148148
case PwPhase.DefendCollect:
149-
// check if enough defenders volunteered — start 30s countdown
150-
var totalSlots = FormedSquads.Sum(s => s.TeamSize);
151-
var totalDefenders = DefenderVotes.Values.Sum(v => v.Count);
152-
if (totalDefenders >= totalSlots)
153-
{
154-
if (defendersFullTime == null) defendersFullTime = DateTime.UtcNow;
155-
}
156-
else
157-
{
158-
defendersFullTime = null;
159-
}
160-
161-
var deadline = GetDefendDeadline();
162-
if (defendersFullTime != null)
163-
{
164-
var earlyDeadline = defendersFullTime.Value.AddSeconds(30);
165-
if (earlyDeadline < deadline) deadline = earlyDeadline;
166-
}
149+
UpdateDefendersFullTime();
167150

168-
if (DateTime.UtcNow > deadline)
151+
if (DateTime.UtcNow > GetEffectiveDefendDeadline())
169152
{
170153
defendersFullTime = null;
171154
RunDefenderAssignment();
@@ -352,16 +335,34 @@ private void RunDefenderAssignment()
352335
}
353336
}
354337

355-
// floating pool fills unfilled slots on other planets (WHR order)
338+
// floating pool fills unfilled slots on other planets (WHR order, respecting faction eligibility)
356339
floatingPool = floatingPool.OrderByDescending(x => defenderWhr.Get(x)).ToList();
340+
341+
// cache defending factions per planet and defender faction IDs
342+
var planetDefendingFactions = new Dictionary<int, List<Faction>>();
343+
foreach (var pid in attackedPlanetIds)
344+
planetDefendingFactions[pid] = GetDefendingFactions(FormedSquads.First(s => s.PlanetID == pid));
345+
346+
var defenderFactionId = new Dictionary<string, int?>();
347+
using (var db = new ZkDataContext())
348+
{
349+
foreach (var name in floatingPool)
350+
{
351+
var user = server.ConnectedUsers.Get(name)?.User;
352+
if (user != null) defenderFactionId[name] = db.Accounts.Find(user.AccountID)?.FactionID;
353+
}
354+
}
355+
357356
foreach (var planetId in attackedPlanetIds)
358357
{
359358
var totalSlotsNeeded = FormedSquads.Where(s => s.PlanetID == planetId).Sum(s => s.TeamSize);
360359
var assigned = assignedDefenders[planetId];
361360
var deficit = totalSlotsNeeded - assigned.Count;
362361
if (deficit > 0 && floatingPool.Count > 0)
363362
{
364-
var toAdd = floatingPool.Take(deficit).ToList();
363+
var allowedFactionIds = planetDefendingFactions[planetId].Select(f => f.FactionID).ToHashSet();
364+
var eligible = floatingPool.Where(x => defenderFactionId.ContainsKey(x) && defenderFactionId[x].HasValue && allowedFactionIds.Contains(defenderFactionId[x].Value)).ToList();
365+
var toAdd = eligible.Take(deficit).ToList();
365366
assigned.AddRange(toAdd);
366367
foreach (var p in toAdd) floatingPool.Remove(p);
367368
}
@@ -544,11 +545,15 @@ private async Task JoinPlanetDefense(int targetPlanetId, string userName)
544545
var account = db.Accounts.Find(user.AccountID);
545546
if (account == null || !account.CanPlayerPlanetWars()) return;
546547

547-
// check this user's faction can defend at least one squad on this planet
548+
// check this user's faction can defend this specific planet
548549
var squadsOnPlanet = FormedSquads.Where(s => s.PlanetID == targetPlanetId).ToList();
549550
if (!squadsOnPlanet.Any()) return;
550551
var defendingFactions = GetDefendingFactions(squadsOnPlanet.First());
551-
if (!defendingFactions.Any(f => f.FactionID == account.FactionID)) return;
552+
if (!defendingFactions.Any(f => f.FactionID == account.FactionID))
553+
{
554+
await server.GhostChanSay(user.Faction, $"{userName} cannot defend {squadsOnPlanet.First().Name} (not owner or allied)");
555+
return;
556+
}
552557

553558
// remove from other planets
554559
foreach (var kv in DefenderVotes)
@@ -558,6 +563,7 @@ private async Task JoinPlanetDefense(int targetPlanetId, string userName)
558563
if (!DefenderVotes[targetPlanetId].Contains(userName))
559564
{
560565
DefenderVotes[targetPlanetId].Add(userName);
566+
UpdateDefendersFullTime();
561567
await server.GhostChanSay(user.Faction, $"{userName} joins defense of {squadsOnPlanet.First().Name}");
562568
await conus.SendCommand(new PwJoinPlanetSuccess() { PlanetID = targetPlanetId });
563569
await UpdateLobby();
@@ -600,6 +606,8 @@ public async Task OnUserDisconnected(string name)
600606
// also remove from formed squads (attacker who disconnected after squad formation)
601607
foreach (var squad in FormedSquads)
602608
changed |= squad.Attackers.RemoveAll(x => x == name) > 0;
609+
610+
if (changed) UpdateDefendersFullTime();
603611
}
604612

605613
if (changed) await UpdateLobby();
@@ -613,7 +621,7 @@ public async Task OnUserDisconnected(string name)
613621

614622
// ===================== LOBBY COMMANDS =====================
615623

616-
public PwMatchCommand GenerateLobbyCommand()
624+
public PwMatchCommand GenerateLobbyCommand(string playerFaction = null)
617625
{
618626
PwMatchCommand command = null;
619627
try
@@ -633,10 +641,30 @@ public PwMatchCommand GenerateLobbyCommand()
633641
}
634642
else if (Phase == PwPhase.DefendCollect)
635643
{
636-
// aggregate per planet: one VoteOption per planet showing total slots needed
644+
// build defending factions cache per planet
645+
var defFactionCache = new Dictionary<int, List<Faction>>();
646+
foreach (var planetId in FormedSquads.Select(s => s.PlanetID).Distinct())
647+
{
648+
if (!defFactionCache.ContainsKey(planetId))
649+
defFactionCache[planetId] = GetDefendingFactions(FormedSquads.First(s => s.PlanetID == planetId));
650+
}
651+
652+
// resolve player's faction ID for filtering
653+
int? playerFactionId = null;
654+
if (playerFaction != null)
655+
{
656+
var fac = factions.FirstOrDefault(f => f.Shortcut == playerFaction);
657+
playerFactionId = fac?.FactionID;
658+
}
659+
660+
// aggregate per planet, filtered to planets this player can defend
637661
var options = new List<PwMatchCommand.VoteOption>();
638662
foreach (var planetId in FormedSquads.Select(s => s.PlanetID).Distinct())
639663
{
664+
// skip planets this player's faction cannot defend
665+
if (playerFactionId != null && !defFactionCache[planetId].Any(f => f.FactionID == playerFactionId))
666+
continue;
667+
640668
var squads = FormedSquads.Where(s => s.PlanetID == planetId).ToList();
641669
var first = squads.First();
642670
var totalNeeded = squads.Sum(s => s.TeamSize);
@@ -655,23 +683,17 @@ public PwMatchCommand GenerateLobbyCommand()
655683
});
656684
}
657685

658-
// collect all defending factions across attacked planets (one DB call per distinct planet, not per squad)
659-
var defFactionCache = new Dictionary<int, List<Faction>>();
660-
foreach (var pid in options.Select(o => o.PlanetID))
661-
{
662-
if (!defFactionCache.ContainsKey(pid))
663-
defFactionCache[pid] = GetDefendingFactions(FormedSquads.First(s => s.PlanetID == pid));
664-
}
665686
var allDefFactions = defFactionCache.Values
666687
.SelectMany(f => f.Select(x => x.Shortcut))
667688
.Distinct()
668689
.ToList();
669690

691+
var effectiveDeadline = GetEffectiveDefendDeadline();
670692
command = new PwMatchCommand(PwMatchCommand.ModeType.Defend)
671693
{
672694
Options = options,
673-
Deadline = GetDefendDeadline(),
674-
DeadlineSeconds = (int)GetDefendDeadline().Subtract(DateTime.UtcNow).TotalSeconds,
695+
Deadline = effectiveDeadline,
696+
DeadlineSeconds = (int)effectiveDeadline.Subtract(DateTime.UtcNow).TotalSeconds,
675697
AttackerFaction = AttackingFaction.Shortcut,
676698
DefenderFactions = allDefFactions
677699
};
@@ -834,20 +856,73 @@ private DateTime GetDefendDeadline()
834856
return PhaseStartTime.AddMinutes(GlobalConst.PlanetWarsMinutesToAccept);
835857
}
836858

859+
/// <summary>
860+
/// Effective defend deadline accounting for the 30s early cutoff when enough defenders join.
861+
/// </summary>
862+
private DateTime GetEffectiveDefendDeadline()
863+
{
864+
var deadline = GetDefendDeadline();
865+
if (defendersFullTime != null)
866+
{
867+
var earlyDeadline = defendersFullTime.Value.AddSeconds(30);
868+
if (earlyDeadline < deadline) deadline = earlyDeadline;
869+
}
870+
return deadline;
871+
}
872+
873+
/// <summary>
874+
/// Check if every attacked planet has enough direct defender volunteers and set/clear the 30s countdown.
875+
/// Each planet must independently have volunteers >= its slots — overflow across factions is not counted.
876+
/// </summary>
877+
private void UpdateDefendersFullTime()
878+
{
879+
var allFull = FormedSquads.Any(); // at least one squad exists
880+
foreach (var planetId in FormedSquads.Select(s => s.PlanetID).Distinct())
881+
{
882+
var slotsNeeded = FormedSquads.Where(s => s.PlanetID == planetId).Sum(s => s.TeamSize);
883+
var volunteered = DefenderVotes.ContainsKey(planetId) ? DefenderVotes[planetId].Count : 0;
884+
if (volunteered < slotsNeeded)
885+
{
886+
allFull = false;
887+
break;
888+
}
889+
}
890+
891+
if (allFull)
892+
{
893+
if (defendersFullTime == null) defendersFullTime = DateTime.UtcNow;
894+
}
895+
else
896+
{
897+
defendersFullTime = null;
898+
}
899+
}
900+
837901
public void RemoveFromRunningBattles(int battleID)
838902
{
839903
RunningBattles.Remove(battleID);
840904
}
841905

842906
private async Task UpdateLobby()
843907
{
844-
await server.Broadcast(server.ConnectedUsers.Values.Where(x => x.User.CanUserPlanetWars()), GenerateLobbyCommand());
908+
if (Phase == PwPhase.DefendCollect)
909+
{
910+
// send per-player filtered options (only planets they can defend)
911+
foreach (var conus in server.ConnectedUsers.Values.Where(x => x.User.CanUserPlanetWars()))
912+
await conus.SendCommand(GenerateLobbyCommand(conus.User.Faction));
913+
}
914+
else
915+
{
916+
await server.Broadcast(server.ConnectedUsers.Values.Where(x => x.User.CanUserPlanetWars()), GenerateLobbyCommand());
917+
}
845918
SaveStateToDb();
846919
}
847920

848921
private Task UpdateLobby(string player)
849922
{
850-
return server.ConnectedUsers.Get(player)?.SendCommand(GenerateLobbyCommand());
923+
var conus = server.ConnectedUsers.Get(player);
924+
if (conus == null) return Task.CompletedTask;
925+
return conus.SendCommand(GenerateLobbyCommand(conus.User.Faction));
851926
}
852927

853928
private void SaveStateToDb()

0 commit comments

Comments
 (0)