Leaderboard-Class instead of KO in Roblox - roblox

i'm creating a game at the moment and i need to know to add a section into the leaderboard like how the KO system works, however i need it to display names of the classes, such as "Wizard" etc. Making them into teams instead makes it too crowded and this would help.

You can add multiple types of values to your leaderboard (leaderstats) object by putting different value objects. For example, if you want to have titles on the leaderboard, you put a StringValue into your leaderstats object.
Code:
local players = game:GetService("Players")
function playerAdded(player)
local leaderstats = Instance.new("Folder")
leaderstats.Parent = player
leaderstats.Name = "leaderstats"
local title = Instance.new("StringValue")
title.Parent = leaderstats
title.Name = "Class"
title.Value = "Wizard" -- or whatever you want it to be
end
players.PlayerAdded:Connect(playerAdded)
To change the class, all you have to do is change the value of the StringValue Class.
player.leaderstats.Class.Value = "Warrior"
References:
https://www.robloxdev.com/articles/Leaderboards
https://www.robloxdev.com/api-reference/event/Players/PlayerAdded
https://www.robloxdev.com/api-reference/class/StringValue

Related

Roblox- how to store large arrays in roblox datastores

i am trying to make a game where players create their own buildings and can then save them for other players to see and play on. However, roblox doesn't let me store all the data needed for the whole creation(there are several properties for each brick)
All i get is this error code:
104: Cannot store Array in DataStore
any help would be greatly appreciated!
I'm not sure if this is the best method, but it's my attempt. Below is an example of a table, you can use tables to store several values. I think you can use HttpService's JSONEncode function to convert tables into strings (which hopefully can be saved more efficiently)
JSONEncode (putting brick's data into a string, which you can save into the DataStore
local HttpService = game:GetService("HttpService")
-- this is an example of what we'll convert into a json string
local exampleBrick = {
["Size"] = Vector3.new(3,3,3),
["Position"] = Vector3.new(0,1.5,0),
["BrickColor"] = BrickColor.new("White")
["Material"] = "Concrete"
}
local brickJSON = HttpService:JSONEncode(exampleBrick)
print(brickJSON)
-- when printed, you'll get something like
-- { "Size": Vector3.new(3,3,3), "Position": Vector3.new(0,1.5,0), "BrickColor": BrickColor.new("White"), "Material": "Concrete"}
-- if you want to refer to this string in a script, surround it with two square brackets ([[) e.g. [[{"Size": Vector3.new(3,3,3)... }]]
JSONDecode (reading the string and converting it back into a brick)
local HttpService = game:GetService("HttpService")
local brickJSON = [[ {"Size": Vector3.new(3,3,3), "Position": Vector3.new(0,1.5,0), "BrickColor": BrickColor.new("White"), "Material": "Concrete"} ]]
function createBrick(tab)
local brick = Instance.new("Part")
brick.Parent = <insert parent here>
brick.Size = tab[1]
brick.Position= tab[2]
brick.BrickColor= tab[3]
brick.Material= tab[4]
end
local brickData = HttpService:JSONDecode(brickJSON)
createBrick(brickData) --this line actually spawns the brick
The function can also be wrapped in a pcall if you want to account for any possible datastore errors.
Encoding a whole model into a string
Say your player's 'building' is a model, you can use the above encode script to convert all parts inside a model into a json string to save.
local HttpService = game:GetService("HttpService")
local StuffWeWantToSave = {}
function getPartData(part)
return( {part.Size,part.Position,part.BrickColor,part.Material} )
end
local model = workspace.Building --change this to what the model is
local modelTable = model:Descendants()
for i,v in pairs(modelTable) do
if v:IsA("Part") or v:IsA("WedgePart") then
table.insert(StuffWeWantToSave, HttpService:JSONEncode(getPartData(modelTable[v])))
end
end
Decoding a string into a whole model
This will probably occur when the server is loading a player's data.
local HttpService = game:GetService("HttpService")
local SavedStuff = game:GetService("DataStoreService"):GetDataStore("blabla") --I don't know how you save your data, so you'll need to adjust this and the rest of the scripts (as long as you've saved the string somewhere in the player's DataStore)
function createBrick(tab)
local brick = Instance.new("Part")
brick.Parent = <insert parent here>
brick.Size = tab[1]
brick.Position= tab[2]
brick.BrickColor= tab[3]
brick.Material= tab[4]
end
local model = Instance.new("Model") --if you already have 'bases' for the players to load their stuff in, remove this instance.new
model.Parent = workspace
for i,v in pairs(SavedStuff) do
if v[1] ~= nil then
CreateBrick(v)
end
end
FilteringEnabled
If your game uses filteringenabled, make sure that only the server handles saving and loading data!! (you probably already knew that) If you want the player to save by clicking a gui button, make the gui button fire a RemoteFunction that sends their base's data to the server to convert it to a string.
BTW I'm not that good at scripting so I've probably made a mistake somehwere.. good luck though
Crabway's answer is correct in that the HttpService's JSONEncode and JSONDecode methods are the way to go about tackling this problem. As it says on the developer reference page for the DataStoreService, Data is ... saved as a string in data stores, regardless of its initial type. (https://developer.roblox.com/articles/Datastore-Errors.) This explains the error you received, as you cannot simply push a table to the data store; instead, you must first encode a table's data into a string using JSONEncode.
While I agree with much of Crabway's answer, I believe the function createBrick would not behave as intended. Consider the following trivial example:
httpService = game:GetService("HttpService")
t = {
hello = 1,
goodbye = 2
}
s = httpService:JSONEncode(t)
print(s)
> {"goodbye":2,"hello":1}
u = httpService:JSONDecode(s)
for k, v in pairs(u) do print(k, v) end
> hello 1
> goodbye 2
As you can see, the table returned by JSONDecode, like the original, uses strings as keys rather than numeric indices. Therefore, createBrick should be written something like this:
function createBrick(t)
local brick = Instance.new("Part")
brick.Size = t.Size
brick.Position = t.Position
brick.BrickColor = t.BrickColor
brick.Material = t.Material
-- FIXME: set any other necessary properties.
-- NOTE: try to set parent last for optimization reasons.
brick.Parent = t.Parent
return brick
end
As for encoding a model, calling GetChildren would produce a table of the model's children, which you could then loop through and encode the properties of everything within. Note that in Crabway's answer, he only accounts for Parts and WedgeParts. You should account for all parts using object:IsA("BasePart") and also check for unions with object:IsA("UnionOperation"). The following is a very basic example in which I do not store the encoded data; rather, I am just trying to show how to check the necessary cases.
function encodeModel(model)
local children = model:GetChildren()
for _, child in ipairs(children) do
if ((child:IsA("BasePart")) or (child:IsA("UnionOperation"))) then
-- FIXME: encode child
else if (child:IsA("Model")) then
-- FIXME: using recursion, loop through the sub-model's children.
end
end
return
end
For userdata, such as Vector3s or BrickColors, you will probably want to convert those to strings when you go to encode them with JSONEncode.
-- Example: part with "Brick red" BrickColor.
color = tostring(part.BrickColor)
print(string.format("%q", color))
> "Bright red"
I suggest what #Crabway said, use HttpService.
local httpService = game:GetService("HttpService")
print(httpService:JSONEncode({a = "b", b = "c"}) -- {"a":"b","b":"c"}
But if you have any UserData values such as Vector3s, CFrames, Color3s, BrickColors and Enum items, then use this library by Defaultio. It's actually pretty nice.
local library = require(workspace:WaitForChild("JSONWithUserdata"))
library:Encode({Vector3.new(0, 0, 0)})
If you want a little documentation, then look at the first comment in the script:
-- Defaultio
--[[
This module adds support for encoding userdata values to JSON strings.
It also supports lists which skip indices, such as {[1] = "a", [2] = "b", [4] = "c"}
Userdata support is implemented by replacing userdata types with a new table, with keys _T and _V:
_T = userdata type enum (index in the supportedUserdataTypes list)
_V = a value or table representing the value
Follow the examples bellow to add suppport for additional userdata types.
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
Usage example:
local myTable = {CFrame.new(), BrickColor.Random(), 4, "String", Enum.Material.CorrodedMetal}
local jsonModule = require(PATH_TO_MODULE)
local jsonString = jsonModule:Encode(myTable)
local decodedTable = jsonModule:Decode(jsonString)
--]]

Create an Array from list of objects in MaxScript and add them to a new layer

I'm super new to Maxscript and want to automate a process, I've been looking at some tutorials, but I'm running into a issue with selection. What I'm trying to do, is I have a list of strings (that I might have to add to) that represent objects in the max file that I want to select (if they exist in that file) and then add to a new layer.
for instance:
/* I have a big long list of objects I want to mass select, this has to be hardcoded because its a similar list that exists in a ton of max files */
rObj1 = "testObj1"
rObj2 = "sampleObj2"
""
rObj99 = "newObj90"
/*I want to then add it to an array
removeList = #(rObj***)
/* Then run through each entry in the array to make sure it exists and then add it to my selection
for i in removeList do
(
if i != undefined then select (i)
)
/*Then Add what I have selected to a new layer
newLayer = LayerManager.newLayerFromName "removed_list"
for obj in selection do newLayer.addNode obj
I keep getting an error when it comes to selection, being new to Max I'm not sure what to do.
You are trying to select string where you should be selecting (or adding to the layer) an object:
newLayer = LayerManager.newLayerFromName "removed_list"
for objName in removeList where isValidNode (getNodeByName objName) do
newLayer.addNode (getNodeByName objName)

Set object properties after setting the object

I've created a class with various properties in VB6.
The properties are
PiccoId
OrderId
UserId
StockCode
Quantity
At the top of the class I have declared 2 instances of classes I'm using.
Dim stkLine As CSOPSLine ' This is the class where the properties are declared and read
Private SOPSLines As cSLine ' This class creates the new objects and sets the property values
When the user enters the order number on a handheld barcode scanner, I'm creating an object to associate with this particular scanner like so:
Set SOPSLines = New cSLine
Set SOPSLines = getSOPSLine(ID, sOrder, "", "", 0)
In the next stage of the process, the user needs to enter their user ID so it can be seen which user scanned in the item.
I need to update the property of this same object, but I'm not sure how - Currently I am trying to do it within my getSOPSLine function, like this:
Dim line As New CSOPSLine
Dim bFound As Boolean
bFound = False
For Each line In SOPSLines.Items
If line.PiccoId = ID Then
line.OrderId = OrderId
line.Quantity = Qty
line.StockCode = stock
line.UserId = UserId
Set getSOPSLine = line
bFound = True
Exit For
End If
Next
If bFound = False Then
Set line = SOPSLines.Add(ID, OrderId, UserId, stock, Qty)
Set getSOPSLine = line
End If
Set line = Nothing
However, as I'm not storing sOrder at class level (Due to the fact multiple users can be using barcode scanners, the order ID can't be kept at class level as other users will just overwrite it),
I'm not sure how once I've got the next variable (In this case, userID, and the other variables after this stage) I can update the same object as I've just created.
I've tried to do something like
Set stkLine = getSOPSLine(ID, stkLine.OrderId, pUser, "", 0)
but it errors saying
object or with block variable has not been set
How can I update the properties of stkLine without constantly creating new objects?
EDIT
To clarify:
When the application receives data from the handheld barcode scanner, a select case is entered, with one case for each of the variables being entered (E.g. Order ID, user ID, stock code etc.)
The first case sets the order ID.
The code here is
Case FRAME_ORDER_SELECTION
On Error Resume Next
Dim sOrder As Long
sOrder = Picco.GetData(ID, 50)
If sOrder = 0 Then
Call Picco.Send(ID, FRAME_ORDER_SELECTION)
Exit Sub
Else
With Picco
Call .ClearForm(ID)
Call .Text(ID, LINE_1, "===== User ID =====")
Call .Text(ID, LINE_2, "")
Call .NewField(ID, 60, 5, FLD_LINE + SND_ENTER)
Call .Send(ID, FRAME_LINE_ADD)
Set SOPSLines = New cSLine
Set SOPSLines = getSOPSLine(ID, sOrder, "", "", 0)
End With
End If
frameid = FRAME_LINE_ADD
m_iLastFrameId = FRAME_ORDER_SELECTION
On Error GoTo Picco_DataArrived_Err
This is where the object is created.
The next case is after the user enters their user ID into the scanner.
Case FRAME_LINE_ADD
On Error Resume Next
Dim pUser As String
pUser = ""
pUser = Picco.GetData(ID, 60)
If pUser = "" Then
Exit Sub
End If
On Error GoTo Picco_DataArrived_Err
With Picco
Call .ClearForm(ID)
Call .Text(ID, LINE_1, "===== Add Line =====")
Call .Text(ID, LINE_2, "")
Call .Text(ID, LINE_7, "Scan or type code")
Call .NewField(ID, FIELD_POS, 18, FLD_LINE + FLD_READER + SND_ENTER)
Call .Send(ID, FRAME_LINE_QTY)
End With
Set stkLine = getSOPSLine(ID, stkLine.OrderId, pUser, "", 0)
frameid = FRAME_LINE_QTY
m_iLastFrameId = FRAME_LINE_ADD
Then there will be 2 or 3 more cases when populating the rest of the required values.
What I need to do, is in the second case (And all other following cases) update the properties of the object created in the first case.
I'm using the getSOPSLine function as this gets the object with the matching barcode scanner ID (As multiple users may be accessing different orders, they need to be kept separate in this way), but I'm not sure how to update the object where the scanner ID matches.
When you call getSOPSLine in each Case, enter some temporary values for the variables that you're not setting.
Example;
In the UserID case: stkLine = getSOPSLine(ID, 0, pUser, "", 0)
Then, in the getSOPSLine() function, change it so that instead of setting the values automatically, it instead only updates them if they don't equal 0, or "", or whichever temporary variables you use.
That way you're updating the same object, but aren't storing data that may get overwritten.
I'm not sure what you're confused about; I think that you must have some misunderstanding of what objects, variables, and properties are that is preventing you from asking this in a way that I understand. I'm not sure how your code lines up with your questions. But I'll give this a shot:
Private SOPSLines As cSLine
Set SOPSLines = New cSLine
Set SOPSLines = getSOPSLine(ID, sOrder, "", "", 0)
This declares a class-level variable, that can hold a cSLine object. That seems reasonable. Then you create a new instance of cSLine to put in that variable. But I don't know why, because you then point the variable to a different instance entirely, which is the instance returned from your getSOPSLine function. That middle line doesn't seem to be doing anything, and I'm not sure what you're trying to do with it.
I've tried to do something like
Set stkLine = getSOPSLine(ID, stkLine.OrderId, pUser, "", 0)
but it errors saying
object or with block variable has not been set
Well, then it sounds like stkLine isn't set to an object. I don't see any code that's trying to set stkLine other than that line. So when you try to get stkLine.OrderId, there isn't an object to get the OrderID property of, so it gives you an error.
I need to update the property of this same object, but I'm not sure how
Well, if there's an object you care about, you probably have it in a variable somewhere. You use variable.property = value syntax to assign value to the property of the object currently stored in variable.
But again, I'm not sure where your confusion is, since you're clearly assigning properties of objects in your code already.
If you're not understanding how objects work in VB, I'd recommend reading through the Working with Objects chapter of the documentation.
And if your confusion lies elsewhere, perhaps you could put together a more specific question about what you're trying to do?

How do I assign usernames to a ROBLOX Team Spawner?

I would like to know how to assign certain usernames to a team spawner.
Basically when a certain username joins the game, they get placed into a team on the leader board and spawn at the correct spawn in game.
You can do this by checking the username and assigning the team. So something like this, assuming you don't have teams already set up.
team = Instance.new("Team",game:GetService'Teams')
game:GetService'Players'.PlayerAdded:connect(function(p)
if p.Name == "name" then
p.Team = team
end
end
Obviously you can set the team name and color through this script or create it your own.
You have to do the player handling yourself. Basically you want to listen on new players with PlayerAdded and set the team (based on some kind of magical function) with Team.
However you can assign Spawners to a team by setting the TeamColor to equal the Team's TeamColor.
Example code:
local Teams = game:GetService("Teams")
local RedTeam = Teams["Red Team"]
local OtherTeam = Teams["Other Team"]
local PlayersInTeamRed = { "Player1" , "Player2" }
game:GetService("Players").PlayerAdded:connect(function(player)
for playerName in ipairs(PlayersInTeamRed) do
if player.Name == playerName then
player.Team = RedTeam
return
end
end
-- Maybe another list here
-- not in "Team red"
player.Team = OtherTeam
end)
Note that you might want to check against the UserId instead, because some players changes their name.
Also make sure that the Spawn's Neutral value is false.

as3 - loop over all text fields?

I have a form in as3 flash with textfields and radio buttons with their "instance name" all set consecutively such as:
field_1
field_2
field_3
...etc
Is there an easy way in AS3 code to loop over all those fields and get their values in an array? Ideally I'd like a simply loop to get the values (so I can add in a simple popup if a value is missing) and then with the filled array simply post it using URLRequest.
Thanks!
If you want a way that's a little less work and more maintainable (if the amount of text can change in the future or you need to reuse the code on other forms or don't want to bother with instance names), then you could do something like the code below.
Keep in mind this assumes all your text fields are children of the same parent and is in the scope of that parent (so on a frame in the timeline that holds all your text fields)
function validateTextFields(){
var tmpTf:TextField;
var i:int = numChildren;
while(i--){ //iterate through all the display objects on this timeline
tmpTf = getChildAt(i) as TextField;
if(tmpTf){
//now that you have the textfield, you can check for an appropriate value, or send the value to a server, or store it in an array etc.
//check if the value is blank, if so set the background to red
if(tmpTf.text == ""){
tmpTf.background = true;
tmpTf.backgroundColor = 0xFF0000;
}else{
tmpTf.background = false;
}
}
}
}
It sounds like you want to use a for statement. I've also used a multi-dimensional array to store the instance names, and the text that they contain. I like to use the variable _path to define the scope of my code.
var _path = this;
var text_ar:Array = new Array(['instance_1',''],['instance_2',''],['instance_3','']); //instance name, instance text.
for(var i=0; i<ar.length; i++)
{
text_ar[i][1] = _path[text_ar[i][0]].text
}
trace( text_ar[1][1] ); //Traces the text that's entered in instance_1.