Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
0

Finding players next to a player on a global leaderboard?

Asked by 2 years ago

Hello. I am trying to make a "finding opponent" system like in Clash of Clans, where you find another player's base who has around the same amount of trophies for you. The trick is that the game needs to find someone who is around the same amount of trophies as the player. All the trophies are stored in a DataStore. All I need to do is to somehow find another player from the DataStore that is around the same amount of trophies as the player.

I honestly have no idea about how to solve this problem, any help would be greatly appreciated!

1 answer

Log in to vote
1
Answered by
imKirda 4491 Moderation Voter Community Moderator
2 years ago

I accidentally looked at the OrderedDataStore documentation and found my solution, the 2 last properties let you specify the minimum and maximum value you are going to look for in a data store, you can use this to only pick values inside of a specified range. For cases where Bob has 100000 trophies but you have 100 trophies the range differs too much so it can't be a known value, instead there is a default range value, if no people in that range is found the range is multiplied by 2 and checks again, for example if with numbers 100000 and 100 the base range is 5000, at first it won't find anything, then it will multiply the range by 2 which will give you 10000, still nothing, it will continue multiplying it -> 20000 -> 40000 -> 80000 -> 160000 and when it comes to 160000, 100000 will be in range, this can require a lot of requests to the data store if the difference between users is huge, you can solve that using task.wait, I did not do that since yes. Here is a module that I wrote for that:

local searchlib = {}

local DataStoreService = game:GetService("DataStoreService")

local data_store

function searchlib.init_data_store(name)
  data_store = DataStoreService:GetOrderedDataStore(name)
end

function searchlib.add_count(key, count)
  local success, response = pcall(data_store.SetAsync, data_store, key, count)

  if not success then
    warn("Failed to add count:", response)
  end
end

function searchlib.get_count(key)
  -- Does not include pcall cuz lazy >wO
  return data_store:GetAsync(key)
end

function searchlib.get_closest_count(count, required, range)
  local closest = {}
  local found = 0

  while true do
    -- Neither does include pcall do yourself noob
    local pages = data_store:GetSortedAsync(false, 50, count - range,
      count + range)

    while true do
      local page = pages:GetCurrentPage()
      if #page == 0 then break end

      for _, save in pairs(page) do
        if closest[save.key] then continue end
        closest[save.key] = save.value
        found += 1
        if found >= required then return closest end
      end

      if pages.IsFinished then break end
      page:AdvanceNextPageAsync()
    end

    range *= 2
  end

  return closest
end

return searchlib

And here it is used by a server script for test cases:

local searchlib = require(script.searchlib)

local players = {
  ["bob"] = 100000,
  ["me"] = 20,
  ["yapelize"] = -100,
  ["feahren"] = 5000,
  ["fish"] = 8000,
  ["opalmime"] = 10000,
  ["weeb"] = 8888888,
  ["iiilllii"] = 69,
  ["ruby"] = 1,
  ["kirda"] = 1013
}

searchlib.init_data_store("test")

for player, trophies in pairs(players) do
  searchlib.add_count(player, trophies)
end

print(
  "closest for 5000 trophies:", searchlib.get_closest_count(5000, 4, 500),
  "closest for 100000 trophies:", searchlib.get_closest_count(100000, 4, 10000),
  "closest for -2000 trophies:", searchlib.get_closest_count(-2000, 4, 300)
)

My output after running the code was the following:

closest for 5000 trophies:  ?  {
                    ["feahren"] = 5000,
                    ["fish"] = 8000,
                    ["kirda"] = 1013,
                    ["opalmime"] = 10000
                 } closest for 100000 trophies:  ?  {
                    ["bob"] = 100000,
                    ["feahren"] = 5000,
                    ["fish"] = 8000,
                    ["opalmime"] = 10000
                 } closest for -2000 trophies:  ?  {
                    ["iiilllii"] = 69,
                    ["me"] = 20,
                    ["ruby"] = 1,
                    ["yapelize"] = -100
                 }

The function get_closest_count takes 3 arguments, the first one is amount of trophies you want to get closest matches for, the second is required amount of matches, it will continue looping until it finds this amount of matched opponents and the third is the base range, for bigger numbers it should be possibly bigger since there is less players with a lot of trophies. init_data_store function initializes the data store with your given name. This module lacks pcalls almost everywhere since that would make it even longer. If you want to use this with your data store without loosing your data you will need to set async all data from your normal data store into this ordered data store.

0
Wow was it there all the time? This is so useful, never seen it before. And you can do a lot of cool stuff with this MrSuperKrut 167 — 2y
1
bullying Xapelize 2658 — 2y
1
i donvote!!!!!!12345654312345604306039402 give me more thropuy Xapelize 2658 — 2y
1
also i xapelize!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!3913019019401290940195051515 Xapelize 2658 — 2y
Ad

Answer this question