- git (download)
- foundry (forge, anvil, cast) (download, make sure to foundryup at least once)
- node.js (v16+) (download)
- pnpm (after installing node: npm install --global pnpm)
- Unity (download)
- The .NET SDK (7.0) (download)
If you are using Windows:
- install git bash (gitforwindows.org)
- install nodejs, including “native modules” (nodejs.org/en/download) (re native modules: just keep the checkmark, it’s enabled by default in the installer)
- Install foundry via foundryup using Git bash
The tutorial repo for this template can be found here.
Run the following command in the root:
pnpm install
Then, open two terminal tabs.
In tab 1:
pnpm run dev:node
In tab 2:
pnpm run dev
In Unity, Open the Main scene if you haven’t already (packages/client/Assets/Scenes/Main.unity)
.
Press play. Click to increment the counter.
MUD Template Unity autogenerates C# definitions for your Tables when you run pnpm dev
. These should appear in packages/client/Assets/Scripts/codegen/
.
var addressKey = net.addressKey;
// get by key
var currentPlayer = PlayerTable.GetTableValue(addressKey);
// currentPlayer is strongly typed
string name = currentPlayer.name;
var playerSubInsert = PlayerTable.OnRecordInsert().ObserveOnMainThread().Subscribe(OnInsertPlayers);
var playerSubUpdate = PlayerTable.OnRecordUpdate().ObserveOnMainThread().Subscribe(OnDeletePlayers);
var playerSubDelete = PlayerTable.OnRecordDelete().ObserveOnMainThread().Subscribe(OnDeletePlayers);
var playerSubDeleteInsert = PlayerTable.OnRecordInsert.Merge(PlayerTable.OnRecordDelete).ObserveOnMainThread().Subscribe(OnInsertDeletePlayers);
private void OnUpdatePlayers(PlayerTableUpdate update)
{
// PlayerTableUpdate has a TypedValue, which is a Tuple of <PlayerTable,PlayerTable>
// Item 1 is the current value, and Item 2 is the previous value.
var currentValue = update.TypedValue.Item1;
if (currentValue == null) return;
var previousValue = update.TypedValue.Item2;
// PlayerTableUpdate inherits from UniMUD's RecordUpdate
// So you can still get the key, table, and untyped values.
var playerPosition = PositionTable.GetTableValue(update.Key);
if (playerPosition == null) return;
var playerSpawnPoint = new Vector3((float)playerPosition.x, 0, (float)playerPosition.y);
var player = Instantiate(playerPrefab, playerSpawnPoint, Quaternion.identity);
if (update.Key == net.addressKey) {
Debug.Log("Is local player");
}
}
This template generates Nethereum bindings for your World contract, which, we can access to make a transaction. Note that not all Unity functions can be async, so you may need to wrap your transaction in a coroutine.
async void Spawn(NetworkManager nm)
{
var addressKey = net.addressKey;
var currentPlayer = PlayerTable.GetTableValue(addressKey);
if (currentPlayer == null)
{
// spawn the player
await nm.worldSend.TxExecute<SpawnFunction>(0, 0);
}
}
// For example, with the UniTask library:
private async UniTaskVoid SendIncrementTxAsync()
{
try
{
await net.worldSend.TxExecute<IncrementFunction>();
}
catch (Exception ex)
{
// Handle your exception here
Debug.LogException(ex);
}
}
You can deploy to any non-local chain with cd packages/contracts && pnpm run deploy:testnet
.
Be sure to properly set the ChainID and RPC urls in the NetworkManager component.
UniMUD currently doesn’t implement the faucet service, so you must manually send testnet funds to your address. Your address is logged in Debug mode, but you can also create a UI component to fetch and display it from the NetworkManager.