Skip to content

Instantly share code, notes, and snippets.

@Earu
Last active April 16, 2022 14:08
Show Gist options
  • Save Earu/9c7c7064188f855c1809cc8c56e8db52 to your computer and use it in GitHub Desktop.
Save Earu/9c7c7064188f855c1809cc8c56e8db52 to your computer and use it in GitHub Desktop.
An advanced Garry's Mod server search query processor.
local function parse_host_name_tags(host_name)
local tags = {}
local function add_tag(tag)
tag = tag:Trim()
if #tag > 1 and #tag < 15 then
table.insert(tags, tag)
end
end
local start_index, _ = host_name:find("[%|%,%-]")
local end_index = 1
while start_index do
local tag = end_index == 1
and host_name:sub(end_index, start_index - 1):Trim()
or host_name:sub(end_index, start_index - 1):gsub("[%[%]%(%)]", ""):Trim()
add_tag(tag)
end_index = start_index + 1
start_index, _ = host_name:find("[%|%,%-]", end_index)
end
local last_tag = host_name:sub(end_index, #host_name):gsub("[%[%]%(%)]", ""):Trim()
add_tag(last_tag)
local explicit_tag_patterns = {
"%[(.+)%]", "%((.+)%)", "%{(.+)%}", "%<(.+)%>",
"%[(.+)$", "%((.+)$", "%{(.+)$", "%<(.+)$",
}
local actual_host_name = (table.remove(tags, 1) or host_name)
for _, tag_pattern in ipairs(explicit_tag_patterns) do
actual_host_name = actual_host_name:gsub(tag_pattern, function(tag)
add_tag(tag)
return ""
end)
end
if #tags <= 0 then
add_tag("N/A")
end
return actual_host_name, tags
end
local valid_filters = {
["host"] = "FullHostName",
["tag"] = "Tags",
["gm"] = "Description",
["map"] = "Map",
["ip"] = "IPAddress",
}
local function default_search_processor(server, search_query)
local has_matching_tag = false
for _, tag in ipairs(server.Tags) do
if tag:lower():find(search_query, 1, true) then
has_matching_tag = true
break
end
end
return server.FullHostName:lower():find(search_query, 1, true)
or server.Description:lower():find(search_query, 1, true)
or server.Map:lower():find(search_query, 1, true)
or server.Gamemode:lower():find(search_query, 1, true)
or server.IPAddress:find(search_query, 1, true)
or has_matching_tag
end
local function parse_search_query(search_query)
if not search_query or #search_query:Trim() <= 0 then
return function(server) return true end
end
local filter_processors = {}
local filters = search_query:Split(";")
for _, filter in ipairs(filters) do
local chunks = filter:Split("=")
local has_valid_filter_value = chunks[2] and #chunks[2] > 0
if has_valid_filter_value then
local filter_type = chunks[1]:Trim():lower()
local filter_value = chunks[2]:lower()
if not valid_filters[filter_type] then
table.insert(filter_processors, function(server) return false end)
continue
end
table.insert(filter_processors, function(server)
local server_value = server[valid_filters[filter_type]]
if not server_value then
return false
end
local server_value_type = type(server_value)
if isstring(server_value) then
return server_value:lower():find(filter_value, 1, true)
elseif server_value_type == "table" then
for _, value in ipairs(server_value) do
if value:lower():find(filter_value, 1, true) then
return true
end
end
return false
else
return tostring(server_value):lower():find(filter_value, 1, true)
end
end)
else
table.insert(filter_processors, function(server) return default_search_processor(server, filter:Trim():lower()) end)
end
end
return function(server)
for _, filter_processor in ipairs(filter_processors) do
if not filter_processor(server) then
return false
end
end
return true
end
end
local function fetch_servers(srv_type, callback, search_query)
serverlist.Query({
Type = srv_type,
Callback = function(ping, host_name, description, map_name, ply_count, max_ply_count, bot_ply_count, has_password, workshop_id, ip_address, gamemode)
local actual_host_name, tags = parse_host_name_tags(host_name)
local server = {
Ping = ping,
FullHostName = host_name,
HostName = actual_host_name,
Tags = tags,
Description = description,
Map = map_name,
PlayerCount = ply_count,
MaxPlayerCount = max_ply_count,
BotPlayerCount = bot_ply_count,
HasPassword = has_password,
WorkshopID = workshop_id,
IPAddress = ip_address,
Gamemode = gamemode,
}
if search_query then
local execute_query = parse_search_query(search_query:lower())
if execute_query(server) then
callback(server)
end
else
callback(server)
end
end,
})
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment