Data Files

Data files are used to store potentially large amounts of arbitrary data.


Using a data file

The GetDatafile method will return a DynamicConfigFile object. If the file requested already exists, its data will be loaded into the DynamicConfigFile. If the file does not exist, it will be created.

Creating/saving the file

DynamicConfigFile dataFile = Interface.Oxide.DataFileSystem.GetDatafile("MyDataFile");

dataFile["EpicString"] = "EpicValue";
dataFile["EpicNumber"] = 42;

dataFile.Save();

Doing this will create a file at the location oxide/data/MyDataFile.json which will have the following contents:

{
    "EpicString" : "EpicValue",
    "EpicNumber" : 42
}

Accessing data by key

// Check if the EpicString exists
if (dataFile["EpicString"] != null)
{
    Puts(dataFile["EpicString"]); // Outputs: EpicValue
}

// Check if the EpicNumber exists
if (dataFile["EpicNumber"] != null)
{
    Puts(dataFile["EpicNumber"]); // Outputs: 42
}

Removing a key

Remove a particular key, using the previous example.

dataFile.Remove("EpicString");
dataFile.Save();

The final JSON output:

{
    "EpicNumber" : 42
}

Clearing the entire file

dataFile.Clear();

Nested keys

A developer may use the DynamicConfigFile object to easily read and write nested key-value pairs.

Write nested key

dataFile["EpicCategory"]["EpicString"] = "EpicValue";
{
    "EpicCategory" : {
        "EpicString" : "EpicValue"
    }
}

Read nested key

if (dataFile["EpicCategory"]["EpicString"] != null)
{
    Puts(dataFile["EpicCategory"]["EpicString"]); // Outputs: EpicValue
}

Checking if a file exists

if (Interface.Oxide.DataFileSystem.ExistsDatafile("MyDataFile"))
{
    Puts("MyDataFile exists!");
}
else
{
    Puts("MyDataFile does not exist");
}

Loading a data object

Much like advanced configurations, data files may be scaffolded using a class definition.

private class StoredData
{
    public HashSet<PlayerInfo> Players = new HashSet<PlayerInfo>();

    public StoredData()
    {
    }
}

private class PlayerInfo
{
    public string Id;
    public string Name;

    public PlayerInfo()
    {
    }

    public PlayerInfo(IPlayer player)
    {
        Id = player.Id;
        Name = player.Name;
    }
}

private StoredData storedData;

private void Init()
{
    storedData = Interface.Oxide.DataFileSystem.ReadObject<StoredData>("MyDataFile");
}

Saving a data object

Change data files by simply assigning the new values and writing the object to the file.

[Command("test")]
private void TestCommand(IPlayer player, string command, string[] args)
{
    PlayerInfo info = new PlayerInfo(player);
    if (storedData.Players.Contains(info))
    {
        player.Reply("Your data has already been added to the file");
    }
    else
    {
        storedData.Players.Add(info);
        player.Reply("Saving your data to the file...");
        Interface.Oxide.DataFileSystem.WriteObject("MyDataFile", storedData);
    }
}

Advanced data

For large plugins that potentially store massive amounts of data, using a single data file may not be advisable. In this case, uMod provides the ability to store many smaller data files in a custom sub-directory. These smaller data files may be loaded on an as-needed basis, thus reducing the impact of a plugin on memory and the filesystem overall.

private DataFileSystem dataFile;

private void Init()
{
    dataFile = new DataFileSystem($"{Interface.Oxide.DataDirectory}\\player_info");
}

private PlayerInfo LoadPlayerInfo(string playerId)
{
    return dataFile.ReadObject<PlayerInfo>($"playerInfo_{playerId}");
}

private void SavePlayerInfo(string playerId, PlayerInfo playerInfo)
{
    dataFile.WriteObject<PlayerInfo>($"playerInfo_{playerId}", playerInfo);
}