Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update #3000

Merged
merged 7 commits into from
Jan 7, 2025
Merged

update #3000

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions Shared/LobbyClient/DedicatedServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public class DedicatedServer : IDisposable
public static EventHandler<SpringBattleContext> AnyDedicatedExited;

private readonly SpringPaths paths;
private readonly Timer timer = new Timer(20000);
private readonly Timer timer = new Timer(1000);

private Dictionary<string, HashSet<byte> > gamePrivateMessages = new Dictionary<string, HashSet<byte> >();

Expand Down Expand Up @@ -514,8 +514,7 @@ private void timer_Elapsed(object sender, ElapsedEventArgs e)
try
{
var timeSinceStart = DateTime.UtcNow.Subtract(Context.StartTime).TotalSeconds;
const int timeToWait = 160; // force start after 180s
const int timeToWarn = 100; // warn people after 120s
const int timeToWait = 160; // force start after this many seconds

if (Context.IsHosting && IsRunning && (Context.IngameStartTime == null))
{
Expand All @@ -524,7 +523,10 @@ private void timer_Elapsed(object sender, ElapsedEventArgs e)
Context.IsTimeoutForceStarted = true;
ForceStart();
}
else if (timeSinceStart > timeToWarn) SayGame($"Game will be force started in {Math.Max(20, timeToWait - Math.Round(timeSinceStart))} seconds");
else
{
talker.SendText($"/luarules pregame_timer_seconds {Convert.ToInt32(timeToWait - timeSinceStart)}");
}
}
}
catch (Exception ex)
Expand Down
2 changes: 2 additions & 0 deletions Shared/LobbyClient/Spring.SpringBattleContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ public class SpringBattleContext

public BattlePlayerResult GetOrAddPlayer(string name)
{
if (string.IsNullOrEmpty(name)) return null; // we don't want to add null players

var ret = ActualPlayers.FirstOrDefault(y => y.Name == name);
if (ret == null)
{
Expand Down
2 changes: 1 addition & 1 deletion Shared/PlasmaShared/GlobalConst.cs
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ public static void OverrideContentServiceClient(IContentServiceClient client)
}


public static string UnitSyncEngine = "unitsync";
public static string UnitSyncEngine = "105.1.1-1485-g78f9a2c";

public static int SteamContributionJarID = 2;
public static Dictionary<ulong, int> DlcToKudos = new Dictionary<ulong, int>() { { 842950, 100 }, { 842951, 250 }, { 842952, 500 } };
Expand Down
5 changes: 4 additions & 1 deletion Zero-K.info/Controllers/TourneyController.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using System.Web.Mvc;
Expand All @@ -17,7 +18,9 @@ public class TourneyModel
public List<int> Team1Ids { get; set; } = new List<int>();
public List<int> Team2Ids { get; set; } = new List<int>();
public string Title { get; set; }
public string ModoptString { get; set; }

[DisplayFormat(ConvertEmptyStringToNull = false)]
public string ModoptString { get; set; } = "";
}

// GET: Tourney
Expand Down
63 changes: 62 additions & 1 deletion ZkLobbyServer/ServerBattle.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
Expand Down Expand Up @@ -70,6 +71,12 @@ public class ServerBattle : Battle

public CommandPoll ActivePoll { get; private set; }

// Dictionary tracking cooldown for each user that fails a poll
private readonly ConcurrentDictionary<string, DateTime> pollFailCooldowns = new ConcurrentDictionary<string, DateTime>();

// Returns the count of non-spectators in the current battle
public int NonSpectatorPlayerCount => Users.Values.Count(x => x!= null && !x.IsSpectator);

public bool IsAutohost { get; private set; }
public bool IsDefaultGame { get; private set; } = true;
public bool IsCbalEnabled { get; private set; } = true;
Expand Down Expand Up @@ -174,7 +181,7 @@ public List<string> GetAllUserNames()
{
var ret = Users.Select(x => x.Key).ToList();
if (spring.IsRunning) ret.AddRange(spring.Context.ActualPlayers.Select(x => x.Name));
return ret.Distinct().ToList();
return ret.Distinct().Where(x=>x!=null).ToList();
}

public BattleCommand GetCommandByName(string name)
Expand Down Expand Up @@ -652,13 +659,48 @@ public async Task<bool> StartVote(Func<string, string> eligibilitySelector, List
await Respond(creator, $"Please wait, another poll already in progress: {ActivePoll.Topic}");
return false;
}

// Check if the user is on cooldown due to a failed poll
if (creator != null && IsOnPollCooldown(creator?.User, out var remain))
{
await Respond(creator, $"You cannot start a vote for {remain} seconds.");
return false;
}


await poll.Setup(eligibilitySelector, options, creator, topic);
ActivePoll = poll;
pollTimer.Interval = timeout * 1000;
pollTimer.Enabled = true;
return true;
}


private bool IsUserModerator(string username)
{
if (Users.TryGetValue(username, out var ubs) && (ubs?.LobbyUser?.IsAdmin == true))
return true;
if (server.ConnectedUsers.TryGetValue(username, out var con) && (con?.User?.IsAdmin == true)) // command can be sent by someone not in the battle
return true;
return false;
}


private bool IsOnPollCooldown(string username, out int remainSeconds)
{
remainSeconds = 0;
if (pollFailCooldowns.TryGetValue(username, out var blockedUntil))
{
var diff = blockedUntil - DateTime.UtcNow;
if (diff.TotalSeconds > 0)
{
remainSeconds = (int)Math.Ceiling(diff.TotalSeconds);
return true;
}
}
return false;
}


public async void StopVote()
{
Expand All @@ -669,7 +711,26 @@ public async void StopVote()
if (ActivePoll != null) await ActivePoll.End(false);
if (pollTimer != null) pollTimer.Enabled = false;
ActivePoll = null;

// Let the poll announce results or do final DB logging
await oldPoll?.PublishResult();


// 1) Did the poll pass?
bool pollPassed = oldPoll?.Outcome?.ChosenOption != null;

// 2) Who started this poll?
string creatorName = oldPoll?.Creator?.User;

// 3) If poll failed and conditions are met => apply 30s cooldown
if (!string.IsNullOrEmpty(creatorName) && // user is known
!pollPassed // poll is a failure
&& IsAutohost // only relevant in autohost
&& NonSpectatorPlayerCount >= 10
&& !IsUserModerator(creatorName))
{
pollFailCooldowns[creatorName] = DateTime.UtcNow.AddSeconds(30);
}
}
catch (Exception ex)
{
Expand Down
2 changes: 1 addition & 1 deletion ZkLobbyServer/autohost/Commands/CmdKick.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ private bool NotifyAdminChannel(ServerBattle battle, Say e, bool isActualKick)
{
gtype = string.Format("game on map {0}", battle.MapName);
PlasmaShared.BattlePlayerResult res = battle.spring.Context.GetOrAddPlayer(target);
isspec = res.IsSpectator;
isspec = res?.IsSpectator == true;
}
else
{
Expand Down
Loading