[PLUGIN] Roda - A Powerful Data Editor - $4.99 Limited Time Offer!

Roda is designed to enhance the process of editing structured data in ModuleScripts. The plugin offers a user-friendly UI with fast, efficient methods and handy features to manage and modify the data of any game component. It can be used to edit items, weapons, skills, perks, buffs, configs, NPCs, dialogs, quests…




Documentation

->GH-Pages



Version: 0.8.19

:orange_square: Before You Buy :orange_square:

Currently, there are no known issues. The plugin was thoroughly tested before its release. However, there may be some edge cases and scenarios that were not considered. Any issues that might arise will be fixed asap.

The only supported data types for now are strings, numbers, and booleans. Please check the docs before buying the plugin.

Launch Price Drop!

discount

Limited Time Offer!

:arrow_right: Get Roda :arrow_left:



Join Roda’s Guilded server


Introduction Video

10 Likes

image
:sob:

1 Like

Is it just me or do I feel like I have to pay 15 bucks to change some variable vals. I don’t want to disrespect this person for his work and amazing UI skills but I just think that nobody wouldn’t want to spend money on a plugin that just changes a few numbers here are there and copy and pastes a few lines.
Then again, apart from the idea, great work.

2 Likes

Hey Mazing, thank you for the reply and sharing your concerns. I thought the capabilities of the plugin would be obvious from the video or the docs, but often, they are only obvious to the developer of the tool.

This plugin is essentially a lightweight database management system. Small projects can benefit from it since it’s more convenient to edit data this way than manually in ModuleScripts. However, the benefits increase with the size of your project.

For clarification, here are some common use cases:

  • Managing variable values, of course.

  • View/select elements by categories by displaying dropdown properties as tabs.

  • The Search Tab is a great way to find specific items that might need changes. The more elements you have to manage, the more beneficial it becomes.

  • If your elements have images, you can actually see the image, rather than looking at a string like “rbxassetid://123…” in code and trying to remember what the image was.

  • You can edit data concurrently in Team Create – e.g., if another Roda user changed the name, price, image, or any other property of an item, these changes are directly synchronized with you.

  • You can lock the data file configuration or the editing of data itself to prevent accidental changes (also locks it for other Roda users in Team Create). This is a helper feature designed to enhance workflow efficiency, not a security/permission measure, since data can still be manually edited in the ModuleScript.

  • Templating - You can create data file configurations and copy these between projects, essentially like creating a schema in a database.

  • Integration with External Tools. For example export the data to your API, from there forward it anywhere else you need. Maybe something like a wiki website where you visualize your game elements. You can also import data back from your API.

  • Export the data to the DataStore and import it back, eliminating the need to edit the DataStore in different ways. It can be used for many kinds of elements (but NOT for player data. For player data there are better solutions out there like sleitnick’s DataStore Editor and similar). The limitation here is having tables as values of keys. Only primitives are supported. If you need tables as values, you would create separate data file configurations (tables) and then link the data at runtime. Like joins in a traditional relational database.

If you have just a few items or elements in your game with variable values in ModuleScript or in the DataStore, you might not see a great benefit from this plugin, other than it maybe being more convenient. However, if you have to manage 50, 100, 500, or more items or elements, then editing and adjusting stuff in code becomes painful.

A typical project in terms of data could look like this:

loleris’s ProfileService/ProfileStore for DataStore interaction.

The profile template would look something like:

local playerStats = {
	money = 0,
	level = 0,
	-- ...
}

local items = {
	{
		id = 0,
		amount = 0,
	},
}

local ProfileTemplate = {
	playerStats = playerStats,
	items = items,
	-- ...
}

The actual items database would be in a ModuleScript, managed with Roda

local module = {
	{
		id = 1,
		name = "Apple",	
		value = 28,
		image = "rbxassetid://12345",
        -- ...
	},
	{
		id = 2,
		name = "Banana",		
		value = 30,
		image = "rbxassetid://123456",
         -- ...
	},
}

I hope this is clearer now.

You can add properties to your items manually, by parsing existing item data, or by selecting from a collection of over 600 game-related properties.

if it was w robux i lowkey would’ve bought and tried it out

if this was free i would definitely use it all the time. 15 bucks is definitely expensive for this. nice plugin tho

1 Like

This reminded of Godot or Unity in-engine feature where you can edit tables, or dictionaries inside the properties panel and its super intuitive! Great work!

the

return {} 

in question

1 Like

The UI seems to be not responsive to the size of the plugin window.


Using 1440p resolution

Very cool, my game has a lot of items where this would be really useful.

If there was a robux version, I would definitely get it.

Hey Ace, thanks for buying and trying out my plugin! It’s my first roblox plugin and first time using React-Lua or React in general. I put most of my effort into the code behind to keep it stable,
but I also tried to make the UI clean and intuitive. I only tested it on a 1080p monitor, so I haven’t checked other resolutions yet. I’ll fix any scaling issues once I get a 1440p monitor.
From your screenshot, the text size looks consistent with Studio’s default, so it should be fine undocked. Let me know if you find any other issues.

1 Like

Can we have more data types and not forced to use data types that are compatible to the Datastore not everyone is gonna use this to do data store editing.

Its so lacking that I decided not to use it its more efficient to write data on the module with data types such as Nested Dictionaries, Nested Arrays, Vector3s and CFrames instead of writing a code to just parse the Vector3s or CFrame values or any nested values.

I would use this just for Gamepasses, Datastores or Badges. But any more complex would take way more time than doing the primitive way.

I would rather want the plugin to let me know that if the data is not supported on the datastore it should just remind me no need to give us any restrictions.

I want to use this for my Tasks Lists but its not compatible and I don’t wanna write a parser just to make it work.
This is the data currently structured hopefully this structure can be supported!

Example:

return {
   ["Task1"] = {
       TaskName = "Task1",
       Weight = 2,
       Priority = 1,
       Roles = {["Chief"] = true, ["Prisoner"] = false, ["Guard"] = false},
       SubTasks = {
            Priority = 1,
            Name = "Fetch Something",
            Tags = {"Pickable", "Throwable"},
            Predicate = function(Player: Player) 
               return Player.UserId == 0000000
            end,
            WaypointPositions = {Vector3.new(2, 3, 5)},
       },
   }
{

I’d love to have Vector3, Color3, CFrame, and so on directly in there. It’d be awesome if it worked, but as you mentioned, it wouldn’t be compatible with DataStores. Therefore, I went with primitives only. The idea of having two different types of schemas (compatible with DataStores and not compatible with DataStores) is actually pretty nice, and I will definitely think about how to make that work. Though, functions as values will probably not be possible unless we can figure out a reasonable way to serialize and visualize them in the UI.

The plugin handles data somewhat like a relational database would. This is needed for the Search Tab, Dropdowns with values from other tables, and so on. So, nested tables are not supported directly but can be easily joined at runtime. The table you provided cannot be inserted into any database type without flattening the structure into multiple tables. It’s, of course, much more work to set up, but it can be beneficial if you have many tasks or want to reuse parts like WaypointPositions or Roles in other places or even other projects.

If you don’t have many complex objects or reusable sections in there, I, too, wouldn’t bother setting up a relational structure for that.

I added to the description that only primitive types are supported for now as values, as I just realized it’s not mentioned in the initial post but only in the “Types” section of the docs.

How about referencing functions to a seperate flat dictionary would that work?
Predicates Module

local predicates = {
	["Predicate1"] = function()
		return true
	end,
	["Predicate2"] = function()
		return false
	end,
}

return predicates

Tasks Database

local tasks = {
	["Task1"] = {
		Name = "Task1",
		Priority = 1,
		Weight = 10,
		Predicate = predicates["Predicate1"]
	}
}

return tasks

That way it can be visualized through the function name possibly? I’m not sure how you do it but i think its possible.

wouldn’t that be inconvenient towards actually using the data though?

I made a simplified example how your TaskList could be implemented in a relational structure. It might be a little bit overkill to set up. You have to decide.

Modules:
TaskList_Modules

For Predicate you could use a module with functions accessible by keys:

local Predicates = {
	["IsAllowedForPlayer"] = function(Player: Player)
		return Player.UserId == 0000000
	end,
}

return Predicates

This is how it would look like in the UI:

At runtime everything can be assembled with something like this:

local TaskListData = game.ServerScriptService.YOUR_PROJECT.Data
local TaskListFunctions = game.ServerScriptService.YOUR_PROJECT.Functions
local PlayerDummy = {UserId = 0000001}

local Tasks = require(TaskListData.Tasks)
local Roles = require(TaskListData.Roles)
local SubTasks = require(TaskListData.SubTasks)
local Tags = require(TaskListData.Tags)
local WaypointPositions = require(TaskListData.WaypointPositions)
local Functions = require(TaskListFunctions.Predicates)

local function assembleTasks()
	local taskList = {}

	for taskKey, taskData in pairs(Tasks) do
		-- Roles
		local rolesTable = {}
		for roleKey, roleData in pairs(Roles) do
			rolesTable[roleKey] = (taskData.Role == roleKey)
		end

		-- SubTasks
		local runtimeSubTasks = {}
		for i = 1, 3 do
			local subTaskKey = taskData["SubTask" .. i]
			if subTaskKey and subTaskKey ~= "None" then
				local subTaskData = SubTasks[subTaskKey]
				if not subTaskData then
					warn("SubTask not found: " .. subTaskKey)
					continue
				end

				-- Tags
				local tagsData = Tags[subTaskData.Tags]
				local tagsList = {}
				for tagKey, tagValue in pairs(tagsData) do
					if tagKey:match("^Tag%d+$") and tagValue ~= "" then
						table.insert(tagsList, tagValue)
					end
				end

				-- WaypointPositions
				local waypointData = WaypointPositions[subTaskData.WaypointPosition]
				if not waypointData then
					warn("WaypointPosition not found: " .. subTaskData.WaypointPosition)
					continue
				end
				local waypointVector = Vector3.new(waypointData.X, waypointData.Y, waypointData.Z)

				-- Predicate
				local predicateFunc = Functions[subTaskData.PredicateKey]
				if not predicateFunc then
					warn("Predicate not found for key: " .. subTaskData.PredicateKey)
				end

				-- SubTask entry
				local runtimeSubTask = {
					Priority = subTaskData.Priority,
					Name = subTaskData.Name,
					Tags = tagsList,
					Predicate = predicateFunc,
					WaypointPositions = { waypointVector },
				}

				table.insert(runtimeSubTasks, runtimeSubTask)
			end
		end

		-- Task entry
		taskList[taskKey] = {
			TaskName = taskData.TaskName,
			Weight = taskData.Weight,
			Priority = taskData.Priority,
			Roles = rolesTable,
			SubTasks = runtimeSubTasks,
		}
	end

	return taskList
end

local taskList = assembleTasks()
print(taskList)

local predicate = taskList["Task1"].SubTasks[1].Predicate(PlayerDummy)
print("IsAllowedForPlayer", predicate)

The resulting table at runtime would then look like the one you posted earlier (with little adjustments for the sake of example):

But now the Tasks can be managed in the UI.

1 Like