Skip to content
Merged
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
1 change: 1 addition & 0 deletions changelog/snippets/fix.6569.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- (#6569) Fix the matchmaker lobby not passing ratings, divisions and clan tags to the session
2 changes: 2 additions & 0 deletions engine/User/CLobby.lua
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ local CLobby = {}
---@field Timeouts any # Read by the engine to determine the behavior of time outs.
---@field CivilianAlliance any # Read by the engine to determine the alliance towards civilians.
---@field GameSpeed any # Read by the engine to determine the behavior of game speed (adjustments).
---@field Ratings table<string, number>
---@field Divisions table<string, string>

---@class UILobbyLaunchGameModsConfiguration
---@field name string # Read by the engine, TODO
Expand Down
87 changes: 75 additions & 12 deletions lua/ui/lobby/autolobby/AutolobbyController.lua
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ local DebugComponent = import("/lua/shared/components/DebugComponent.lua").Debug
local AutolobbyServerCommunicationsComponent = import("/lua/ui/lobby/autolobby/components/AutolobbyServerCommunicationsComponent.lua")
.AutolobbyServerCommunicationsComponent

local AutolobbyArgumentsComponent = import("/lua/ui/lobby/autolobby/components/AutolobbyArguments.lua").AutolobbyArgumentsComponent

local AutolobbyMessages = import("/lua/ui/lobby/autolobby/AutolobbyMessages.lua").AutolobbyMessages

local AutolobbyEngineStrings = {
Expand Down Expand Up @@ -62,6 +64,7 @@ local AutolobbyEngineStrings = {
---@field DIV string # Related to rating/divisions
---@field SUBDIV string # Related to rating/divisions
---@field PL number # Related to rating/divisions
---@field PlayerClan string

---@alias UIAutolobbyConnections boolean[][]
---@alias UIAutolobbyStatus UIPeerLaunchStatus[]
Expand All @@ -86,7 +89,7 @@ local AutolobbyEngineStrings = {
---@field DesiredPeerId UILobbyPeerId

--- Responsible for the behavior of the automated lobby.
---@class UIAutolobbyCommunications : moho.lobby_methods, DebugComponent, UIAutolobbyServerCommunicationsComponent
---@class UIAutolobbyCommunications : moho.lobby_methods, DebugComponent, UIAutolobbyServerCommunicationsComponent, UIAutolobbyArgumentsComponent
---@field Trash TrashBag
---@field LocalPeerId UILobbyPeerId # a number that is stringified
---@field LocalPlayerName string # nickname
Expand All @@ -100,15 +103,15 @@ local AutolobbyEngineStrings = {
---@field LobbyParameters? UIAutolobbyParameters # Used for rejoining functionality
---@field HostParameters? UIAutolobbyHostParameters # Used for rejoining functionality
---@field JoinParameters? UIAutolobbyJoinParameters # Used for rejoining functionality
AutolobbyCommunications = Class(MohoLobbyMethods, AutolobbyServerCommunicationsComponent, DebugComponent) {
AutolobbyCommunications = Class(MohoLobbyMethods, AutolobbyServerCommunicationsComponent, AutolobbyArgumentsComponent, DebugComponent) {

---@param self UIAutolobbyCommunications
__init = function(self)
self.Trash = TrashBag()

self.LocalPeerId = "-2"
self.LocalPlayerName = "Charlie"
self.PlayerCount = tonumber(GetCommandLineArg("/players", 1)[1]) or 2
self.PlayerCount = self:GetCommandLineArgumentNumber("/players", 2)
self.HostID = "-2"

self.GameMods = {}
Expand Down Expand Up @@ -147,20 +150,21 @@ AutolobbyCommunications = Class(MohoLobbyMethods, AutolobbyServerCommunicationsC
end

-- retrieve team and start spot
info.Team = tonumber(GetCommandLineArg("/team", 1)[1])
info.StartSpot = tonumber(GetCommandLineArg("/startspot", 1)[1]) or -1 -- TODO
info.Team = self:GetCommandLineArgumentNumber("/team", -1)
info.StartSpot = self:GetCommandLineArgumentNumber("/startspot", -1)

-- determine army color based on start location
info.PlayerColor = GameColors.MapToWarmCold(info.StartSpot)
info.ArmyColor = GameColors.MapToWarmCold(info.StartSpot)

-- retrieve rating
info.DEV = tonumber(GetCommandLineArg("/deviation", 1)[1]) or 500
info.MEAN = tonumber(GetCommandLineArg("/mean", 1)[1]) or 1500
info.NG = tonumber(GetCommandLineArg("/numgames", 1)[1]) or 0
info.DIV = (GetCommandLineArg("/division", 1)[1]) or ""
info.SUBDIV = (GetCommandLineArg("/subdivision", 1)[1]) or ""
info.DEV = self:GetCommandLineArgumentNumber("/deviation", 500)
info.MEAN = self:GetCommandLineArgumentNumber("/mean", 1500)
info.NG = self:GetCommandLineArgumentNumber("/numgames", 0)
info.DIV = self:GetCommandLineArgumentString("/division", "")
info.SUBDIV = self:GetCommandLineArgumentString("/subdivision", "")
info.PL = math.floor(info.MEAN - 3 * info.DEV)
info.PlayerClan = self:GetCommandLineArgumentString("/clan", "")

return info
end,
Expand Down Expand Up @@ -193,7 +197,7 @@ AutolobbyCommunications = Class(MohoLobbyMethods, AutolobbyServerCommunicationsC
}

-- process game options from the command line
for name, value in Utils.GetCommandLineArgTable("/gameoptions") do
for name, value in self:GetCommandLineArgumentArray("/gameoptions") do
if name and value then
options[name] = value
else
Expand Down Expand Up @@ -294,6 +298,59 @@ AutolobbyCommunications = Class(MohoLobbyMethods, AutolobbyServerCommunicationsC
return 'Ready'
end,

---@param self UIAutolobbyCommunications
---@param playerOptions UIAutolobbyPlayer[]
---@return table<string, number>
CreateRatingsTable = function(self, playerOptions)
---@type table<string, number>
local allRatings = {}

for slot, options in pairs(playerOptions) do
if options.Human and options.PL then
allRatings[options.PlayerName] = options.PL
end
end

return allRatings
end,

---@param self UIAutolobbyCommunications
---@param playerOptions UIAutolobbyPlayer[]
---@return table<string, string>
CreateDivisionsTable = function(self, playerOptions)
---@type table<string, string>
local allDivisions = {}

for slot, options in pairs(playerOptions) do
if options.Human and options.PL then
if options.DIV ~= "unlisted" then
local division = options.DIV
if options.SUBDIV and options.SUBDIV ~= "" then
division = division .. ' ' .. options.SUBDIV
end
allDivisions[options.PlayerName] = division
end
end
end

return allDivisions
end,

---@param self UIAutolobbyCommunications
---@param playerOptions UIAutolobbyPlayer[]
---@return table<string, string>
CreateClanTagsTable = function(self, playerOptions)
local allClanTags = {}

for slot, options in pairs(playerOptions) do
if options.PlayerClan then
allClanTags[options.PlayerName] = options.PlayerClan
end
end

return allClanTags
end,

--- Verifies whether we can launch the game.
---@param self UIAutolobbyCommunications
---@param peerStatus UIAutolobbyStatus
Expand Down Expand Up @@ -488,6 +545,12 @@ AutolobbyCommunications = Class(MohoLobbyMethods, AutolobbyServerCommunicationsC
self:SendPlayerOptionToServer(ownerId, 'Faction', playerOptions.Faction)
end

-- tuck them into the game options. By all means a hack, but
-- this way they are available in both the sim and the UI
Comment on lines +548 to +549
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
-- tuck them into the game options. By all means a hack, but
-- this way they are available in both the sim and the UI
-- tuck them into the game options. By all means a hack, but
-- this way they are available in both the sim (for replays) and the UI

self.GameOptions.Ratings = self:CreateRatingsTable(self.PlayerOptions)
self.GameOptions.Divisions = self:CreateDivisionsTable(self.PlayerOptions)
self.GameOptions.ClanTags = self:CreateClanTagsTable(self.PlayerOptions)

-- create game configuration
local gameConfiguration = {
GameMods = self.GameMods,
Expand All @@ -496,7 +559,7 @@ AutolobbyCommunications = Class(MohoLobbyMethods, AutolobbyServerCommunicationsC
Observers = {},
}

-- send it to all players and tell them to launch
-- send it to all players and tell them to launch with the configuration
self:BroadcastData({ Type = "Launch", GameConfig = gameConfiguration })
self:LaunchGame(gameConfiguration)
end
Expand Down
127 changes: 127 additions & 0 deletions lua/ui/lobby/autolobby/components/AutolobbyArguments.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
--******************************************************************************************************
--** Copyright (c) 2024 Willem 'Jip' Wijnia
--**
--** Permission is hereby granted, free of charge, to any person obtaining a copy
--** of this software and associated documentation files (the "Software"), to deal
--** in the Software without restriction, including without limitation the rights
--** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
--** copies of the Software, and to permit persons to whom the Software is
--** furnished to do so, subject to the following conditions:
--**
--** The above copyright notice and this permission notice shall be included in all
--** copies or substantial portions of the Software.
--**
--** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
--** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
--** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
--** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
--** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
--** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
--** SOFTWARE.
--******************************************************************************************************

--- A component that represent all the supported lobby <-> server communications.
---@class UIAutolobbyArgumentsComponent
AutolobbyArgumentsComponent = ClassSimple {

--- Represent all valid command line arguments for the lobby
ArgumentKeys = {
["/init"] = true,
["/joincustom"] = true,
["/gpgnet"] = true,

-- related to player info
["/clan"] = true,
["/country"] = true,
["/numgames"] = true,

-- related to player settings
["/team"] = true,
["/uef"] = true,
["/cybran"] = true,
["/aeon"] = true,
["/seraphim"] = true,
["/startspot"] = true,

-- related to rating
["/deviation"] = true,
["/mean"] = true,

-- related to divisions
["division"] = true,
["/subdivision"] = true,

-- related to game settings
["/gameoptions"] = true,
["/players"] = true,
},

--- Verifies that it is an expected command line argument
---@param self UIAutolobbyArgumentsComponent | UIAutolobbyCommunications
---@param option string
---@return boolean
ValidCommandLineKey = function(self, option)
if not self.ArgumentKeys[option] then
self:DebugWarn("Unknown command line argument: ", option)
return false
end

return true
end,

--- Attempts to retrieve a string-like command line argument
---@param self UIAutolobbyArgumentsComponent | UIAutolobbyCommunications
---@param option string
---@param default string
---@return string
GetCommandLineArgumentString = function(self, option, default)
if not self:ValidCommandLineKey(option) then
return default
end

-- try to get the first argument
local arguments = GetCommandLineArg(option, 1)
if arguments and (not option[ arguments[1] ]) then
return arguments[1]
end

return default
end,

--- Attempts to retrieve a number-like command line argument
---@param self UIAutolobbyArgumentsComponent | UIAutolobbyCommunications
---@param option string
---@param default number
---@return number
GetCommandLineArgumentNumber = function(self, option, default)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if verifying as thoroughly as checking types is necessary, it just adds to the load of thinking which function is best to use without improving the solution to the original issue: The guards in lobby.lua were implemented to prevent the case of the client giving a command line argument /arg X /arg2 ... where X is an empty string, and GetCommandLineArg(option, 1) would end up returning {"/arg2"} because an empty string is not a token.

if not self:ValidCommandLineKey(option) then
return default
end

-- try to get the first argument and parse it as a number
local arguments = GetCommandLineArg(option, 1)
if arguments and (not option[ arguments[1] ]) then
local parsed = tonumber(arguments[1])
if parsed then
return parsed
else
self:DebugWarn("Failed to parse as a number: ", arguments[1], " for key ", option)
return default
end
end

return default
end,

--- Attempts to retrieve a table-like command line argument
---@param self UIAutolobbyArgumentsComponent | UIAutolobbyCommunications
---@param option string
---@return table<string, string>
GetCommandLineArgumentArray = function(self, option)
if not self:ValidCommandLineKey(option) then
return {}
end
Comment on lines +120 to +123
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the utils function will return an empty table for a non-existent key, so if we don't want to verify if a requested command line key is valid, then this function is not necessary as the default empty table return value is already implemented.


return import("/lua/system/utils.lua").GetCommandLineArgTable(option)
end,
}
5 changes: 3 additions & 2 deletions scripts/LaunchFAInstances.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ $gameName = "MyGame"

# Array of factions to choose from
$factions = @("UEF", "Seraphim", "Cybran", "Aeon")
$clans = @("Yps", "Nom", "Cly", "Mad", "Gol", "Kur", "Row", "Jip", "Bal", "She")

# Get the screen resolution (for placing and resizing the windows)
Add-Type -AssemblyName System.Windows.Forms
Expand Down Expand Up @@ -91,7 +92,7 @@ if ($players -eq 1) {
$hostLogFile = "host_dev_1.log"
$hostFaction = $factions | Get-Random
$hostTeamArgument = Get-TeamArgument -instanceNumber 0
$hostArguments = "/log $hostLogFile /showlog /hostgame $hostProtocol $port $hostPlayerName $gameName $map /startspot 1 /players $players /$hostFaction $hostTeamArgument $baseArguments"
$hostArguments = "/log $hostLogFile /showlog /hostgame $hostProtocol $port $hostPlayerName $gameName $map /startspot 1 /players $players /$hostFaction $hostTeamArgument $baseArguments /division HostDivision /subdivision 1 /clan $($clans | Get-Random)"

# Launch host game instance
Launch-GameInstance -instanceNumber 1 -xPos 0 -yPos 0 -arguments $hostArguments
Expand All @@ -107,7 +108,7 @@ if ($players -eq 1) {
$clientPlayerName = "ClientPlayer_$($i + 1)"
$clientFaction = $factions | Get-Random
$clientTeamArgument = Get-TeamArgument -instanceNumber $i
$clientArguments = "/log $clientLogFile /joingame $hostProtocol localhost:$port $clientPlayerName /startspot $($i + 1) /players $players /$clientFaction $clientTeamArgument $baseArguments"
$clientArguments = "/log $clientLogFile /joingame $hostProtocol localhost:$port $clientPlayerName /startspot $($i + 1) /players $players /$clientFaction $clientTeamArgument $baseArguments /division Diamond /subdivision $($i + 1) /clan $($clans | Get-Random)"

Launch-GameInstance -instanceNumber ($i + 1) -xPos $xPos -yPos $yPos -arguments $clientArguments
}
Expand Down
Loading