Can't store complex data set generated from a PluginScript before runtime

  1. What do you want to achieve? I made a plugin that has various functions for a custom pathfinding system which I intend to use on a very large game world. To use one of the functions as the example for this post, there’s a function that generates a grid of nodes. For now, these nodes are stored in a table. I want to take the table from the PluginScript, which is ran before runtime of course (still editing in Studio), and move it to a separate ModuleScript to be accessed at runtime (studio playtest or live game server).

  2. What is the issue?
    The issue is that if I use require() on the separate ModuleScript from inside the PluginScript and change the data, that data does not persist outside of whatever isolated context the ModuleScript gets loaded in (hope that makes sense). So if I go to the explorer and edit the ModuleScript, nothing has changed. (I assume that this is intended behavior.) Curiously, if I require() the module from the command line and print its contents, or print its contents from within the PluginScript, it will show the correct data. Really not sure what environment ModuleScripts get loaded in when editing in Studio.

  3. What solutions have you tried so far?
    I looked into using the DataStoreService, but given the exceptionally large size of my game world (and consequently the exceptionally large size of the data table), it makes using the DataStoreService inefficient or impossible due to various request rate and data size limits. I then thought perhaps I could force the ModuleScript changes to persist by accessing the source code, or maybe store the data on my own external server, but because the data would have to be stored as text or encoded in JSON, that would turn my custom object classes into “null” along with any built-in ROBLOX object classes (I’m aware I could technically serialize the data and reconstruct it after-the-fact but given the complexity of the total data set I’m considering that as a last resort). I also considered Plugin:SetSetting() but a real server isn’t going to have access to that file, and I don’t think I can properly store the types of data I’m working with through that method anyway. I did search through various online forms including DevForum but this is seemingly an issue particular to my situation.

I’ve provided a simplified example to represent what I’m trying to achieve.

--This is the PluginScript
local storage = require(game.ServerStorage.PathfindingData) 
--PathfindingData exists as the following in this example
--[[
local module = {}
module.grids = {}
return module
]]
local function generateGrid()
    local grid = {}
    --Code adds various nodes to the grid, pretend grid is filled with data
    return grid
end
local newGrid = generateGrid()
table.insert(storage.grids,newGrid) 
--[[The contents of storage.grids in PathfindingData hasn't actually changed outside of the isolated context the ModuleScript was loaded into;
If I try to edit PathfindingData, storage.grids/module.grids is still an empty table]]

I’m not too sure what you’re trying to achieve. Do you mean that you’re trying to edit a module’s source by manipulating what is returned from require? If so, I don’t think there is any easy way to do this, you’d have to directly edit the source property of the module. As for obtaining the data, you could require it once the game first loads up and then append to the source as you’re modifying the require result.

Well, the normal way to change the data in a ModuleScript at runtime is to require() the module, and then change its data. Example:

local moduleScript = require(game.ServerStorage.ModuleScript)
moduleScript.testTable = {5,2,3}

At runtime, this would have the following practical effect on the ModuleScript:

local module = {
    testTable = {5,2,3}
}
return module
--[[I know this is not literally how this works but I hope you get my meaning. 
The data that other scripts read from the ModuleScript has effectively changed.
]]

--Other script
print(require(game.ServerStorage.ModuleScript).testTable) -- {5,2,3}

However, when trying that code before runtime, such as when running a PluginScript, the ModuleScript is unaffected:

local module = {}
return module
--Nothing has changed

--Other script
print(require(game.ServerStorage.ModuleScript).testTable) -- nil

Running that code from the plugin actually has no lasting effect on the data inside the ModuleScript. That’s my dilemma. I’m running the PluginScript which generates a data set and I need to store it inside a ModuleScript, but because the PluginScript executes before runtime, it’s not possible to modify the data inside the ModuleScript using the above example. In essence, I need some way to permanently change the ModuleScript from the PluginScript, preferably without the direct approach of doing:

game.ServerStorage.ModuleScript.Source = ""

The data set generated for the pathfinding system is extremely complex and trying to serialize the data would be a nightmare so I’d like to avoid that if possible.

I see that makes sense, I am not sure if there’s a way without directly modifying the source and without serialization in some way since most things are ruled out:

  • Services that use JSON encoding (incl. datastores) can’t store your custom classes without serialization.
  • Module require results do not persist across script permission contexts (for lack of a better word) or across real threads (actors). For example requiring a module from a local script at runtime and the command line at runtime are 2 different contexts; manipulating on command line doesn’t replicate to local script. Likewise requiring from a script under one actor and another script from another actor, changes to the require result won’t persist. Should a player rejoin, the table would have been removed from memory and thus a brand new module would be required.

I guess that leaves instances maybe but again that probably isn’t ideal, but depending on the type of data you’re saving it might be plausible if it’s only going to be accessed by the server. Roblox servers are very powerful I would assume. I’m not too sure if there are any options beyond that.

1 Like

ROBLOX servers are powerful for most cases, but I mentioned it’s a very large game world and there’s a lot of different resource intensive systems at play, so resources are already at a premium and representing every piece of data physically is not ideal as you guessed. It seems like you’re saying that serialization is the only option. I’m not entirely sure how I’m going to go about doing that, but thanks for at least confirming that it is necessary before I went down that rabbit hole. I was really excited to finally finish creating the pathfinding system and (in retrospect foolishly) assumed there was some overlap between the context of manipulating ModuleScripts from a PluginScript and a normal script, so that throws a wrench in things. Thanks again though!

1 Like