Skip to content
Merged
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
140 changes: 79 additions & 61 deletions osu.Game/Online/Chat/StandAloneChatDisplay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,10 @@ public StandAloneChatDisplay(bool postingTextBox = false)
Channel.BindValueChanged(channelChanged);
}

private readonly Bindable<Dictionary<ModType, IReadOnlyList<Mod>>> availableMods = new Bindable<Dictionary<ModType, IReadOnlyList<Mod>>>();

[BackgroundDependencyLoader(true)]
private void load(ChannelManager manager, BeatmapModelDownloader beatmaps, BeatmapLookupCache beatmapsCache, OsuConfigManager config)
private void load(ChannelManager manager, BeatmapModelDownloader beatmaps, BeatmapLookupCache beatmapsCache, OsuConfigManager config, OsuGameBase game)
{
channelManager ??= manager;
beatmapsDownloader = beatmaps;
Expand All @@ -179,6 +181,8 @@ private void load(ChannelManager manager, BeatmapModelDownloader beatmaps, Beatm

Scheduler.Add(() => broadcastServer.Add(chatBroadcaster));
Scheduler.Add(processMessageQueue);

availableMods.BindTo(game.AvailableMods);
}

protected override void LoadComplete()
Expand Down Expand Up @@ -459,89 +463,103 @@ private void processChatCommands(string[] parts)
break;

string[] mods = parts[2].Split("+");
List<Mod> modInstances = new List<Mod>();
List<Mod> requiredMods = new List<Mod>();
List<Mod> allowedMods = new List<Mod>();

foreach (string mod in mods)
if (mods.Length == 1 && mods[0].Equals(@"fm", StringComparison.OrdinalIgnoreCase))
Comment thread
ILW8 marked this conversation as resolved.
{
if (mod.Length < 2)
{
Logger.Log($@"[!mp mods] Unknown mod '{mod}', ignoring", LoggingTarget.Runtime, LogLevel.Important);
continue;
}

string modAcronym = mod[..2];
var rulesetInstance = RulesetStore.GetRuleset(itemToEdit.RulesetID)?.CreateInstance();

if (rulesetInstance == null)
{
Logger.Log($@"[!mp mods] Couldn't create ruleset instance with ruleset ID {itemToEdit.RulesetID}, ignoring mod '{mod}'",
LoggingTarget.Runtime, LogLevel.Important);
continue;
}
// hardcode freemod to allow all mods, leaves requiredMods empty
var newAllowedMods = availableMods.Value
.SelectMany(pair => pair.Value)
.SelectMany(ModUtils.FlattenMod)
.Where(mod => ModUtils.IsValidFreeModForMatchType(mod, Client.Room?.Settings.MatchType ?? MatchType.TeamVersus));

Mod? modInstance;

// mod with no params
if (mod.Length == 2)
allowedMods.AddRange(newAllowedMods);
}
else // handle regular mods
{
foreach (string mod in mods)
{
modInstance = ParseMod(rulesetInstance, modAcronym, Array.Empty<object>());
if (modInstance != null)
modInstances.Add(modInstance);
continue;
}
if (mod.Length < 2)
{
Logger.Log($@"[!mp mods] Unknown mod '{mod}', ignoring", LoggingTarget.Runtime, LogLevel.Important);
continue;
}

// mod has parameters
{
JsonNode? modParamsNode;
string modAcronym = mod[..2];
var rulesetInstance = RulesetStore.GetRuleset(itemToEdit.RulesetID)?.CreateInstance();

try
if (rulesetInstance == null)
{
modParamsNode = JsonNode.Parse(mod[2..]);
Logger.Log($@"[!mp mods] Couldn't create ruleset instance with ruleset ID {itemToEdit.RulesetID}, ignoring mod '{mod}'",
LoggingTarget.Runtime, LogLevel.Important);
continue;
}
catch (JsonException)

Mod? modInstance;

// mod with no params
if (mod.Length == 2)
{
modParamsNode = null;
modInstance = ParseMod(rulesetInstance, modAcronym, Array.Empty<object>());
if (modInstance != null)
requiredMods.Add(modInstance);
continue;
}

if (modParamsNode is JsonArray modParams)
// mod has parameters
{
List<object> parsedParamsList = new List<object>();
JsonNode? modParamsNode;

foreach (JsonNode? node in modParams)
try
{
modParamsNode = JsonNode.Parse(mod[2..]);
}
catch (JsonException)
{
if (node?.GetValueKind() is not (JsonValueKind.Number or JsonValueKind.False or JsonValueKind.True))
continue;
modParamsNode = null;
}

if (node.AsValue().TryGetValue(out int parsedInt))
{
parsedParamsList.Add(parsedInt);
continue;
}
if (modParamsNode is JsonArray modParams)
{
List<object> parsedParamsList = new List<object>();

if (node.AsValue().TryGetValue(out double parsedDouble))
foreach (JsonNode? node in modParams)
{
parsedParamsList.Add(parsedDouble);
continue;
if (node?.GetValueKind() is not (JsonValueKind.Number or JsonValueKind.False or JsonValueKind.True))
continue;

if (node.AsValue().TryGetValue(out int parsedInt))
{
parsedParamsList.Add(parsedInt);
continue;
}

if (node.AsValue().TryGetValue(out double parsedDouble))
{
parsedParamsList.Add(parsedDouble);
continue;
}

if (node.AsValue().TryGetValue(out bool parsedBool))
parsedParamsList.Add(parsedBool);
}

if (node.AsValue().TryGetValue(out bool parsedBool))
parsedParamsList.Add(parsedBool);
modInstance = ParseMod(rulesetInstance, modAcronym, parsedParamsList);
if (modInstance != null)
requiredMods.Add(modInstance);
}
else
{
Logger.Log($@"[!mp mods] Couldn't parse mod parameter(s) '{mod[2..]}', ignoring", LoggingTarget.Runtime, LogLevel.Important);
}

modInstance = ParseMod(rulesetInstance, modAcronym, parsedParamsList);
if (modInstance != null)
modInstances.Add(modInstance);
}
else
{
Logger.Log($@"[!mp mods] Couldn't parse mod parameter(s) '{mod[2..]}', ignoring", LoggingTarget.Runtime, LogLevel.Important);
}
}
}

if (!ModUtils.CheckCompatibleSet(modInstances))
if (!ModUtils.CheckCompatibleSet(requiredMods))
{
Logger.Log($@"[!mp mods] Mods {string.Join(", ", modInstances.Select(mod => mod.Acronym))} are not compatible together", LoggingTarget.Runtime, LogLevel.Important);
Logger.Log($@"[!mp mods] Mods {string.Join(", ", requiredMods.Select(mod => mod.Acronym))} are not compatible together", LoggingTarget.Runtime, LogLevel.Important);
break;
}

Expand All @@ -562,8 +580,8 @@ private void processChatCommands(string[] parts)
BeatmapID = beatmapInfo.OnlineID,
BeatmapChecksum = beatmapInfo.MD5Hash,
RulesetID = itemToEdit.RulesetID,
RequiredMods = modInstances.Select(mod => new APIMod(mod)).ToArray(),
AllowedMods = Array.Empty<APIMod>()
RequiredMods = requiredMods.Select(mod => new APIMod(mod)).ToArray(),
AllowedMods = allowedMods.Select(mod => new APIMod(mod)).ToArray(),
};

selectionOperation = operationTracker.BeginOperation();
Expand Down