![]() |
VOOZH | about |
dotnet add package Nethereum.Mud --version 6.1.0
NuGet\Install-Package Nethereum.Mud -Version 6.1.0
<PackageReference Include="Nethereum.Mud" Version="6.1.0" />
<PackageVersion Include="Nethereum.Mud" Version="6.1.0" />Directory.Packages.props
<PackageReference Include="Nethereum.Mud" />Project file
paket add Nethereum.Mud --version 6.1.0
#r "nuget: Nethereum.Mud, 6.1.0"
#:package Nethereum.Mud@6.1.0
#addin nuget:?package=Nethereum.Mud&version=6.1.0Install as a Cake Addin
#tool nuget:?package=Nethereum.Mud&version=6.1.0Install as a Cake Tool
Nethereum.Mud provides core infrastructure for interacting with MUD (Onchain Engine) applications. MUD is a framework for building ambitious Ethereum applications with on-chain state management using an Entity-Component-System (ECS) architecture.
MUD (Onchain Engine) is a framework for building complex, composable applications on Ethereum. It provides:
Nethereum.Mud brings this power to .NET, enabling you to build MUD clients, indexers, and tools in C#.
dotnet add package Nethereum.Mud
MUD organizes on-chain applications using several core concepts:
The World is the central registry contract that contains:
Every MUD application has one World contract address.
Namespaces organize related tables and systems:
"Land", "Inventory", "Combat"Tables store on-chain data in structured key-value format:
playerId, itemId)Example table structure:
Table: "Player"
Keys: [playerId: uint256]
Values: [name: string, level: uint8, health: uint16]
Systems are smart contracts containing application logic:
"MoveSystem", "CraftingSystem", "TradeSystem"Resources are identified by namespace:name:
tb type (e.g., "Game:Player" → 0x7462...)sy type (e.g., "Game:MoveSystem" → 0x7379...)bytes32 resource IDsMUD's composability model allows:
MUD tables are typically code-generated from mud.config.ts. Use .nethereum-gen.multisettings for C# generation:
Create .nethereum-gen.multisettings in your contracts directory:
{
"paths": ["mud.config.ts"],
"generatorConfigs": [
{
"baseNamespace": "MyGame.Tables",
"basePath": "../MyGame/Tables",
"generatorType": "MudTables"
},
{
"baseNamespace": "MyGame.Systems",
"basePath": "../MyGame/Systems",
"generatorType": "MudExtendedService"
}
]
}
1. MudTables - Generates table record classes:
2. MudExtendedService - Generates system service classes:
From a MUD config defining a Player table:
// Auto-generated from mud.config.ts
public partial class PlayerTableRecord : TableRecord<PlayerKey, PlayerValue>
{
public PlayerTableRecord() : base("MyWorld", "Player") { }
public class PlayerKey
{
[Parameter("uint256", "playerId", 1)]
public BigInteger PlayerId { get; set; }
}
public class PlayerValue
{
[Parameter("string", "name", 1)]
public string Name { get; set; }
[Parameter("uint8", "level", 2)]
public byte Level { get; set; }
[Parameter("uint16", "health", 3)]
public ushort Health { get; set; }
}
}
# Using Nethereum.Generators.JavaScript
npm install -g nethereum-codegen
# Generate from mud.config.ts
nethereum-codegen generate
Or use the VS Code Solidity extension with multisettings support: https://github.com/juanfranblanco/vscode-solidity
MUD uses custom encoding for efficient on-chain storage:
Table schemas are encoded into bytes32:
using Nethereum.Mud.EncodingDecoding;
var schema = SchemaEncoder.GetSchemaEncoded<PlayerKey, PlayerValue>(resourceId);
Console.WriteLine($"Key schema: {schema.KeySchema.ToHex()}");
Console.WriteLine($"Value schema: {schema.ValueSchema.ToHex()}");
Console.WriteLine($"Static fields: {schema.NumStaticFields}");
Console.WriteLine($"Dynamic fields: {schema.NumDynamicFields}");
Keys are encoded as fixed 32-byte chunks:
var playerRecord = new PlayerTableRecord
{
Keys = new PlayerTableRecord.PlayerKey { PlayerId = 42 }
};
// Encoded as: 0x000000000000000000000000000000000000000000000000000000000000002a
var encodedKey = playerRecord.GetEncodedKey();
Values are encoded in two parts:
1. Static Data - Fixed-size fields (uint256, address, bool, etc.):
// Static fields packed tightly
// e.g., uint8 + uint16 = 3 bytes total
2. Dynamic Data - Variable-size fields (string, bytes, arrays):
// Prefixed with EncodedLengths (packed field lengths)
// Then concatenated dynamic data
Example:
var playerRecord = new PlayerTableRecord
{
Keys = new PlayerTableRecord.PlayerKey { PlayerId = 1 },
Values = new PlayerTableRecord.PlayerValue
{
Name = "Alice",
Level = 5,
Health = 100
}
};
var encodedValues = playerRecord.GetEncodeValues();
Console.WriteLine($"Static data: {encodedValues.StaticData.ToHex()}");
Console.WriteLine($"Dynamic data: {encodedValues.DynamicData.ToHex()}");
Console.WriteLine($"Encoded lengths: {encodedValues.EncodedLengths.ToHex()}");
Decode on-chain data back to typed records:
// Decode from on-chain bytes
playerRecord.DecodeKey(encodedKeyBytes);
playerRecord.DecodeValues(encodedValueBytes);
Console.WriteLine($"Player {playerRecord.Keys.PlayerId}: {playerRecord.Values.Name}");
Console.WriteLine($"Level {playerRecord.Values.Level}, Health {playerRecord.Values.Health}");
using Nethereum.Mud;
using Nethereum.Web3;
// Table record with key and values
var playerRecord = new PlayerTableRecord();
// Set key
playerRecord.Keys = new PlayerTableRecord.PlayerKey
{
PlayerId = 42
};
// Set values
playerRecord.Values = new PlayerTableRecord.PlayerValue
{
Name = "Alice",
Level = 10,
Health = 100
};
// Encode for on-chain storage
var encodedKey = playerRecord.GetEncodedKey();
var encodedValues = playerRecord.GetEncodeValues();
// Decode from on-chain data
playerRecord.DecodeKey(encodedKeyBytes);
playerRecord.DecodeValues(encodedValuesBytes);
Console.WriteLine($"Player {playerRecord.Keys.PlayerId}: {playerRecord.Values.Name}");
using Nethereum.Mud.TableRepository;
// Create in-memory repository
var repository = new InMemoryTableRepository<PlayerTableRecord>();
// Add records
var player1 = new PlayerTableRecord
{
Keys = new() { PlayerId = 1 },
Values = new() { Name = "Alice", Level = 10, Health = 100 }
};
var player2 = new PlayerTableRecord
{
Keys = new() { PlayerId = 2 },
Values = new() { Name = "Bob", Level = 5, Health = 50 }
};
await repository.UpsertAsync(player1);
await repository.UpsertAsync(player2);
// Query by key
var record = await repository.GetByKeyAsync(player1.GetEncodedKey());
Console.WriteLine($"Found player: {record.Values.Name}");
// Query all records
var allPlayers = await repository.GetAsync();
Console.WriteLine($"Total players: {allPlayers.Count}");
using Nethereum.Mud.TableRepository;
var repository = new InMemoryTableRepository<PlayerTableRecord>();
// Add multiple records
// ...
// Query with predicate builder
var predicate = new TablePredicateBuilder<PlayerTableRecord>()
.Where(player => player.Values.Level > 5)
.And(player => player.Values.Health >= 50)
.Build();
var results = await repository.GetAsync(predicate);
foreach (var player in results)
{
Console.WriteLine($"Player {player.Keys.PlayerId}: Level {player.Values.Level}, Health {player.Values.Health}");
}
using Nethereum.Mud.TableRepository;
// Repository with change tracking
var repository = new InMemoryChangeTrackerTableRepository<PlayerTableRecord>();
// Modify records
var player = await repository.GetByKeyAsync(encodedKey);
player.Values.Level += 1;
player.Values.Health -= 10;
await repository.UpsertAsync(player);
// Get all changes since last checkpoint
var changeSet = repository.GetChangeSet();
Console.WriteLine($"Added: {changeSet.AddedRecords.Count}");
Console.WriteLine($"Updated: {changeSet.UpdatedRecords.Count}");
Console.WriteLine($"Deleted: {changeSet.DeletedRecords.Count}");
// Clear change tracking
repository.ClearChangeSet();
using Nethereum.Mud.EncodingDecoding;
// Create resource ID for a table (returns bytes32)
var playerTableResourceId = ResourceEncoder.EncodeTable("Game", "Player");
Console.WriteLine($"Table Resource ID: {playerTableResourceId.ToHex()}");
// Create resource ID for a system
var moveSystemResourceId = ResourceEncoder.EncodeSystem("Game", "MoveSystem");
Console.WriteLine($"System Resource ID: {moveSystemResourceId.ToHex()}");
// Create resource ID for a namespace
var gameNamespaceId = ResourceEncoder.EncodeNamespace("Game");
Console.WriteLine($"Namespace Resource ID: {gameNamespaceId.ToHex()}");
// Decode a resource ID back to its components
var decoded = ResourceEncoder.Decode(playerTableResourceId);
Console.WriteLine($"Namespace: {decoded.Namespace}, Name: {decoded.Name}");
using Nethereum.Mud.EncodingDecoding;
// Get schema for a table record type
var schema = SchemaEncoder.GetSchemaEncoded<PlayerKey, PlayerValue>(resourceId);
Console.WriteLine($"Key schema: {schema.KeySchema.ToHex()}");
Console.WriteLine($"Value schema: {schema.ValueSchema.ToHex()}");
Console.WriteLine($"Total static fields: {schema.NumStaticFields}");
Console.WriteLine($"Total dynamic fields: {schema.NumDynamicFields}");
using Nethereum.Mud.TableRepository;
// Connect to remote table repository API
var httpHelper = new RestHttpHelper(new HttpClient());
var apiClient = new StoredRecordRestApiClient(httpHelper, "https://api.example.com/mud");
// Query specific table
var records = await apiClient.GetRecordsAsync<PlayerTableRecord>(
worldAddress: "0xWorldAddress",
tableId: playerTableResource.ResourceIdEncoded.ToHex()
);
foreach (var record in records)
{
Console.WriteLine($"Player {record.Keys.PlayerId}: {record.Values.Name}");
}
// Query with filters
var filteredRecords = await apiClient.GetRecordsAsync<PlayerTableRecord>(
worldAddress: "0xWorldAddress",
tableId: playerTableResource.ResourceIdEncoded.ToHex(),
filter: $"Level gt 5"
);
using Nethereum.Mud.TableRepository;
// StoredRecord is the persisted form of a table record
var storedRecord = new StoredRecord
{
WorldAddress = "0xWorldAddress",
TableId = playerTableResource.ResourceIdEncoded.ToHex(),
Key0 = encodedKey[0].ToHex(), // First key component
StaticData = encodedStaticData.ToHex(),
DynamicData = encodedDynamicData.ToHex(),
EncodedLengths = encodedLengths.ToHex(),
IsDeleted = false
};
// Convert to table record
var mapper = new StoredRecordDTOMapper<PlayerTableRecord>();
var tableRecord = mapper.MapFromStoredRecord(storedRecord);
Console.WriteLine($"Restored player {tableRecord.Keys.PlayerId}");
Some MUD tables have no keys (configuration singletons):
using Nethereum.Mud;
// Singleton table record
public class ConfigTableRecord : TableRecordSingleton<ConfigValue>
{
public ConfigTableRecord() : base("MyWorld", "Config") { }
public class ConfigValue
{
[Parameter("uint256", "maxPlayers", 1)]
public BigInteger MaxPlayers { get; set; }
[Parameter("bool", "isPaused", 2)]
public bool IsPaused { get; set; }
}
}
// Usage
var config = new ConfigTableRecord();
config.Values = new ConfigTableRecord.ConfigValue
{
MaxPlayers = 100,
IsPaused = false
};
// Only has values, no keys
var encodedValues = config.GetEncodeValues();
using Nethereum.Mud;
using Nethereum.Mud.TableRepository;
using Nethereum.Web3;
// Initialize repository with change tracking
var playerRepository = new InMemoryChangeTrackerTableRepository<PlayerTableRecord>();
var inventoryRepository = new InMemoryChangeTrackerTableRepository<InventoryTableRecord>();
// Load initial state from chain or database
// ...
// Application logic modifies records
var player = await playerRepository.GetByKeyAsync(encodedPlayerId);
player.Values.Level += 1;
player.Values.Health = 100;
await playerRepository.UpsertAsync(player);
var inventory = await inventoryRepository.GetByKeyAsync(encodedInventoryKey);
inventory.Values.Quantity -= 1;
await inventoryRepository.UpsertAsync(inventory);
// Get changes to sync with chain
var playerChanges = playerRepository.GetChangeSet();
var inventoryChanges = inventoryRepository.GetChangeSet();
// Batch changes for on-chain transaction
var allChanges = new List<TableRecordChangeSet>
{
playerChanges,
inventoryChanges
};
// Send to chain via MUD World contract
// (See Nethereum.Mud.Contracts for World interaction)
// Clear change tracking after sync
playerRepository.ClearChangeSet();
inventoryRepository.ClearChangeSet();
Base class for MUD table records with keys.
public abstract class TableRecord<TKey, TValue> : ITableRecord
where TKey : class, new()
where TValue : class, new()
{
public TKey Keys { get; set; }
public TValue Values { get; set; }
public List<byte[]> GetEncodedKey();
public EncodedValues GetEncodeValues();
public void DecodeKey(List<byte[]> encodedKey);
public void DecodeValues(EncodedValues encodedValues);
}
Base class for tables without keys (singletons).
public abstract class TableRecordSingleton<TValue> : ITableRecordSingleton
where TValue : class, new()
{
public TValue Values { get; set; }
public EncodedValues GetEncodeValues();
public void DecodeValues(EncodedValues encodedValues);
}
Interface for table record storage and querying.
public interface ITableRepository<TTableRecord> where TTableRecord : ITableRecord, new()
{
Task<TTableRecord> GetByKeyAsync(List<byte[]> key);
Task<List<TTableRecord>> GetAsync();
Task<List<TTableRecord>> GetAsync(TablePredicate<TTableRecord> predicate);
Task UpsertAsync(TTableRecord record);
Task DeleteAsync(List<byte[]> key);
}
Static utility for creating and decoding MUD resource identifiers (bytes32).
public static class ResourceEncoder
{
public static byte[] EncodeTable(string @namespace, string name);
public static byte[] EncodeSystem(string @namespace, string name);
public static byte[] EncodeNamespace(string @namespace);
public static byte[] EncodeOffchainTable(string @namespace, string name);
public static byte[] EncodeRootTable(string name);
public static byte[] EncodeRootSystem(string name);
public static Resource Decode(byte[] resourceBytes);
}
using Nethereum.Mud.EncodingDecoding;
// Custom key encoding
var customKeys = KeyEncoderDecoder.EncodeKey(new MyKey
{
PlayerId = 1,
ItemId = 42
});
// Custom value encoding
var customValues = ValueEncoderDecoder.EncodeValues(new MyValue
{
Quantity = 10,
IsActive = true
});
using Nethereum.Mud.EncodingDecoding;
// Get field layout for a schema
var fieldLayout = FieldLayoutEncoder.Encode(
staticFieldLengths: new List<byte> { 32, 32, 1 }, // uint256, uint256, bool
numDynamicFields: 2 // Two dynamic fields (bytes or arrays)
);
using Nethereum.Mud;
// Register custom resource types
ResourceTypeRegistry.Register("CustomType", 0x1234);
// Get resource type
var tableType = ResourceTypeRegistry.GetResourceTypeId("Table"); // 0x7462...
var systemType = ResourceTypeRegistry.GetResourceTypeId("System"); // 0x7379...
Keep MUD table data in memory for fast reads, sync changes to chain:
// In-memory repositories for all tables
var repositories = new Dictionary<string, object>
{
["Player"] = new InMemoryChangeTrackerTableRepository<PlayerTableRecord>(),
["Inventory"] = new InMemoryChangeTrackerTableRepository<InventoryTableRecord>(),
// ...
};
// User interacts locally
// Changes tracked automatically
// Periodic sync to chain
await SyncAllChangesToChainAsync(repositories);
// Load initial state from REST API
var httpHelper = new RestHttpHelper(new HttpClient());
var apiClient = new StoredRecordRestApiClient(httpHelper, "https://api.mud.game");
var records = await apiClient.GetRecordsAsync<PlayerTableRecord>(worldAddress, tableId);
var localRepo = new InMemoryTableRepository<PlayerTableRecord>();
foreach (var record in records)
{
await localRepo.UpsertAsync(record);
}
// Work offline
// ...
// Sync back when online
var changes = GetLocalChanges();
await SyncToChainAsync(changes);
// Subscribe to on-chain table updates
// (See Nethereum.Mud.Contracts for event subscriptions)
void OnStoreSetRecordEvent(StoreSetRecordEventDTO evt)
{
var storedRecord = evt.ToStoredRecord();
var tableRecord = mapper.MapFromStoredRecord<PlayerTableRecord>(storedRecord);
// Update local repository
await repository.UpsertAsync(tableRecord);
// Notify UI
NotifyUIOfUpdate(tableRecord);
}
MUD applications are inherently composable:
All state lives on-chain in structured tables:
MUD provides automatic state sync:
Store_SetRecord, Store_DeleteRecordMUD enables complex on-chain applications:
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 net5.0 was computed. net5.0-windows net5.0-windows was computed. net6.0 net6.0 is compatible. net6.0-android net6.0-android was computed. net6.0-ios net6.0-ios was computed. net6.0-maccatalyst net6.0-maccatalyst was computed. net6.0-macos net6.0-macos was computed. net6.0-tvos net6.0-tvos was computed. net6.0-windows net6.0-windows was computed. net7.0 net7.0 was computed. net7.0-android net7.0-android was computed. net7.0-ios net7.0-ios was computed. net7.0-maccatalyst net7.0-maccatalyst was computed. net7.0-macos net7.0-macos was computed. net7.0-tvos net7.0-tvos was computed. net7.0-windows net7.0-windows was computed. net8.0 net8.0 is compatible. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 is compatible. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 netcoreapp2.0 was computed. netcoreapp2.1 netcoreapp2.1 was computed. netcoreapp2.2 netcoreapp2.2 was computed. netcoreapp3.0 netcoreapp3.0 was computed. netcoreapp3.1 netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 netstandard2.0 is compatible. netstandard2.1 netstandard2.1 was computed. |
| .NET Framework | net451 net451 is compatible. net452 net452 was computed. net46 net46 was computed. net461 net461 is compatible. net462 net462 was computed. net463 net463 was computed. net47 net47 was computed. net471 net471 was computed. net472 net472 was computed. net48 net48 was computed. net481 net481 was computed. |
| MonoAndroid | monoandroid monoandroid was computed. |
| MonoMac | monomac monomac was computed. |
| MonoTouch | monotouch monotouch was computed. |
| Tizen | tizen40 tizen40 was computed. tizen60 tizen60 was computed. |
| Xamarin.iOS | xamarinios xamarinios was computed. |
| Xamarin.Mac | xamarinmac xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos xamarinwatchos was computed. |
Showing the top 4 NuGet packages that depend on Nethereum.Mud:
| Package | Downloads |
|---|---|
|
Nethereum.Mud.Contracts
Nethereum.Mud.Contracts Nethereum Web3 Class Library integrate with the Mud framework contracts https://mud.dev/ World, WorldFactory, Core systems and deployment |
|
|
Nethereum.Mud.Repositories.EntityFramework
Nethereum.Mud.Repositories.EntityFramework Nethereum Web3 Class Library providing the EF context Table Repositories to sync with the Store contracts of the Mud framework https://mud.dev/ (Encoding, Repositories, Resources, Schema, TableRecords) |
|
|
FrontierSharp.MudIndexer
Package Description |
|
|
Nethereum.MudBlazorComponents
Nethereum.MudBlazorComponents Nethereum MudBlazor Components to dynamically generate Deploy, Transact and Query smart contracts user interfaces using Deployment and Function Typed Messages or Nethereum Services. Mud.dev Table components to query and upsert data using TableServices. |
Showing the top 1 popular GitHub repositories that depend on Nethereum.Mud:
| Repository | Stars |
|---|---|
|
ChainSafe/web3.unity
🕹 Unity SDK for building games that interact with blockchains.
|
| Version | Downloads | Last Updated |
|---|---|---|
| 6.1.0 | 809 | 3/25/2026 |
| 6.0.4 | 248 | 3/18/2026 |
| 6.0.3 | 192 | 3/18/2026 |
| 6.0.1 | 240 | 3/17/2026 |
| 6.0.0 | 218 | 3/16/2026 |
| 5.8.0 | 224 | 1/6/2026 |
| 5.0.0 | 338 | 5/28/2025 |
| 4.29.0 | 268 | 2/10/2025 |
| 4.28.0 | 276 | 1/7/2025 |
| 4.27.1 | 430 | 12/24/2024 |
| 4.27.0 | 267 | 12/24/2024 |
| 4.26.0 | 332 | 10/1/2024 |
| 4.25.0 | 278 | 9/19/2024 |
| 4.21.4 | 279 | 8/9/2024 |
| 4.21.3 | 261 | 7/22/2024 |
| 4.21.2 | 949 | 6/26/2024 |
| 4.21.1 | 257 | 6/26/2024 |
| 4.21.0 | 296 | 6/18/2024 |