I have looked around and have found a number of questions which approach using-a-string-to-define-the-class-name and dynamic-class-generation-in-coffeescript> but neither of them exactly address my problem, so I am wondering whether I making some fundamental mistake in my approach to the problem.
In the loop below I am looping through some data parsed from JSON. For each set of data I want to extend my class Robot with string = new Robot where string is a string.
Currently my code does not produce any errors, and successfully creates new Robots but since their name is a string, trying to access them with robot1.move() or robot2.doSomeOtherClassyThing() does not work and tells me they are undefined.
This seems like it should not require a verbose helper function to make it work. What am I missing here?
createRobots: -> # process robot commands
createXcoord = missionData.xCoord
createYcoord = missionData.yCoord
createOrient = missionData.orientation
createInstru = missionData.robotInstructions
for command in createOrient
robot = 'robot' + (_i + 1)
name = robot
robot = new Robot \ # create named Robot
name
, createXcoord[_i]
, createYcoord[_i]
, createOrient[_i]
, createInstru[_i]
console.log(robot)
I think what is happening is that the variable "robot = 'string' is written over when the robot = new Robot is declared.
The outcome I am hoping for is string1 = new Robot, "string2 = new Robot". Does that make sense? jsfiddle.net/7EN5y/1
You need to add them to a context. If you want them to be global, create a variable like this:
# Either the browser root, or the CommonJS (e.g. Node) module root
root = window or exports
If you want an object that holds robots, add such an object to the root.
root.robots = []
Then when creating robots, add them to such an object.
robot = 'robot' + (_i + 1)
name = robot
robot = new Robot # ...
root[name] = robot # or robots[name] = robot
You may then use code like robot1.move(), or robots.robot1.move() (depending on if you attached them to the root or not).
Related
I'm trying to create new vector layer with the same fields as contained in original layer.
original_layer_fields_list = original_layer.fields().toList()
new_layer = QgsVectorLayer("Point", "new_layer", "memory")
pr = new_layer.dataProvider()
However, when I try:
for fld in original_layer_fields_list:
type_name = fld.typeName()
pr.addAttributes([QgsField(name = fld.name(), typeName = type_name)])
new_layer.updateFields()
QgsProject.instance().addMapLayer(new_layer)
I get a layer with no fields in attribute table.
If I try something like:
for fld in original_layer_fields_list:
if fld.type() == 2:
pr.addAttributes([QgsField(name = fld.name(), type = QVariant.Int)])
new_layer.updateFields()
QgsProject.instance().addMapLayer(new_layer)
... it works like charm.
Anyway ... I'd rather like the first solution to work in case if one wants to automate the process and not check for every field type and then find an appropriate code. Besides - I really am not able to find any documentation about codes for data types. I managed to find this post https://gis.stackexchange.com/questions/353975/get-only-fields-with-datatype-int-in-pyqgis where in comments Kadir pointed on this sourcecode (https://codebrowser.dev/qt5/qtbase/src/corelib/kernel/qvariant.h.html#QVariant::Type).
I'd really be thankful for any kind of direction.
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)
--]]
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)
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?
I am having a model which takes two input & multiplies them & give the output.
output_1 = input_1 * input_2
I have declared my simulink signals as CustomStorageClass= GetSet
input_1 = Simulink.Signal;
input_1.CoderInfo.StorageClass = 'Custom';
input_1.CoderInfo.CustomStorageClass = 'GetSet';
input_1.CoderInfo.CustomAttributes.GetFunction = 'Get_input_1';
input_1.CoderInfo.CustomAttributes.SetFunction = 'Set_input_1';
input_1.CoderInfo.CustomAttributes.HeaderFile = 'signals.h';
input_2 = Simulink.Signal;
input_2.CoderInfo.StorageClass = 'Custom';
input_2.CoderInfo.CustomStorageClass = 'GetSet';
input_2.CoderInfo.CustomAttributes.GetFunction = 'Get_input_2';
input_2.CoderInfo.CustomAttributes.SetFunction = 'Set_input_2';
input_2.CoderInfo.CustomAttributes.HeaderFile = 'signals.h';
output_1 = Simulink.Signal;
output_1.CoderInfo.StorageClass = 'Custom';
output_1.CoderInfo.CustomStorageClass = 'GetSet';
output_1.CoderInfo.CustomAttributes.GetFunction = 'Get_output_1';
output_1.CoderInfo.CustomAttributes.SetFunction = 'Set_output_1';
output_1.CoderInfo.CustomAttributes.HeaderFile = 'signals.h';
Now I am trying to convert my model to code using simulink coder.
In code generation setting of the model i have selected ert.tlc file in the system target file settings.
But the generated code does not have a Get_input_1() or Get_input_2() call like shown in this link.
http://www.mathworks.com/help/ecoder/ug/getset-custom-storage-classes.html
What i have missed in the setting. Please suggest
I know you probably already solved this issue, but I have also seen this behavior before.
Sometimes MATLAB does not update the header files correctly. If you had set a different configuration for your variable and then made a change involving the header files, I would recommend erasing the *_ert_rtw and slprj folders (they will appear again). It is similar to doing a "Make clean" operation, to ensure that everything is brand new.