New Ethereum talks, every Monday. The week's conference uploads by event, in your inbox.

Loading player…

Build a 3D world with MUD and Unity - Lermchair

ETHGlobalMon, Oct 9, 2023, 12:00 AM

Join Lermchair from Lattice for a workshop titled "Build a 3D world with MUD and Unity". We invite you to join the first virtual Autonomous Worlds hackathon, where participants will explore the potential of multi-author Worlds by developing onchain games, worlds, and art projects. Leverage the power of MUD, a new framework designed for ambitious Ethereum applications, and follow in the footsteps of dozens of teams that have already built unique projects with it, including OPCraft — an onchain voxel world, EVM Factorio, real-time strategy games, and more. By working with the MUD framework, participants will not only contribute to the growth of these worlds but also deepen the understanding of the concept of Autonomous Worlds and its implications in technology and digital collaboration. ----------------- Follow us: https://twitter.com/ETHGlobal​ Check us out: https://ethglobal.co​m Email us at: hello@ethglobal.com

Transcript

foreign [Music] hello everyone and welcome to the lattice Workshop build a 3D World with mud and unity joining us today is learn chair who will be taking us through this session and with that I will pass it over to learn chair to get the session started all right everyone um I'm learned chair as far as you know um and what we're going to be building today is a multiplayer game in unity and mud so we're basically in this game you can drive around little tanks and drop bombs on top of each other and all this is going to happen on chain so first thing you're going to do is clone the repo so repo's name tank mode Dash tutorial and you can find out this link and we'll be working off the main branch but there is a pull request open called final and that has all finished code for the tutorial and um you shall have all the prerequisites like unity.net sck install as well so once you click on that I'm going to go ahead and open the scene in unity oops so go ahead and open the scene in unity thank you and you should see something like this if you don't see something like this then you have to actually open the scene so you go into scenes over here and click on Main and so this project uses a package called Yuna mud which you can find in the package manager if you go here and it's installed from note that this is pre-alpha software so it's not even part of the official like mud package yet so you probably shouldn't use it for anything beyond this hackathon so just to make sure we have something that works in the beginning let's go into our resources folder here oh one sec someone wants a link we're going to go into our resource folder here and we're going to drag in a our tank prefab just anywhere in the scene and and now if we just hit play on the editor you can see I can left click to move my tank around and I can also hold down e and have like a little targeting thing I can use um eventually if I click on a tank I can draw the bottom top of it but for now like this is what we have none this is on chain so we're actually going to delete this because we don't really need it yet so I'll try some contracts um so if you haven't done so already we're going to do first is open the project in our terminal and I'm going to run pnpm install in the root and once everything's installed uh we're going to start modeling our data my assumption is that you guys already have some understanding of mud in solidity so we're not going to be spending too much time on this but basically the smart contract code you right here is exactly the same as in any other non-muni project so we want tanks that can move around and attack each other in our mod config we're going to have a position table and this will have an X and A Y that is in 32. we'll also have any health syllables we actually don't need this scheme of thing as well so for example we have a player at your table as well you can also just write the the type directly if we only have one thing you don't really need to specify the schema and we also have a damage which is a new one 32. this is missing it and finally we want to be able to perform reverse lookups on the position as well so we're going to add the keys with value module for a position this looks like this anyway so now if we go back to our terminal we can CD into packages slash contracts and I'm going to run pnpm run table today so ablegen also runs when you do like pmpm run Dev in the root but that also does a bunch of other stuff and right now now we just want to generate the tables facility it's not starting the movement system so open movement system in your in your loader and we're going to implement this move function so the move function takes in a destination X and Y and basically moves our play to that destination we're going to be using the position table so import that first and we also need the keys with value module as well okay so we'll start by getting the player's current position from the position table and then we'll use the keys of value module to check if there is say a position player at that position that is what it seemed we want to get the position front position table and the value would be positioned in code X and Y oops and we will rename this to a player position so what this is doing is it's returning a list of all keys that have a value of x and y in the position table if that list has keys in it that means there's something out position X and Y so basically we check to make sure no one's at that position and we just check the length of that table so let's see what we require um length to be zero and if not then we'll tell them that position is occupied and if everything goes well then it can set the position so that would be position dot set right here X and Y look at the chat okay next thing we want to do is spawn player pretty straightforward hit the player key again we have to check in if player has already been spawned so this is require not clear but yeah so we'll get the value of the player key this bike's 32 value over here so I'm going to play table if it doesn't exist in the player table that means the player hasn't spawned yet you also need to import the player table here and finally we just set all the components and that's how we create our player when when they spawn in so we'll set half the 100 damage to 10 just because last smart contract to write is attacking so we have an attack system here as well um a player can attack at a certain X and Y location because our bombs we want our bombs to do damage in the radius we're also going to get like all the surrounding tiles within a radius of one from like the center of whatever X and Y you input here so that's nine times nine tiles we're checking in total so you can just uncomment all this and we have to make sure we import our tables as well and basically all you have to do is uncomment everything so for each top well we'll check if there's a player at that position and we'll use the keys of value module over here again check if there's entity at the position we're interested in attacking if there is we'll perform the attack by subtracting the attacker's damage value from The Defenders health value when Health reaches zero just delete everything and that's how we despawn or kill the player okay contracts are done so back to community so how do we connect your new to the chain first thing you have to do is in your hierarchy we're going to create a new ntk object in our scene by right clicking and hitting create empty and we're going to name this network manager and in the inspector on the right we're going to attach the network manager component to it and this is the component that comes with the unit unified package and make sure you set the chain id231337 which is the local chain and you don't have to worry about contract address or private key um because these will be Auto populated for us later okay so now let's test if this works just to make sure we can connect to the chain so we're going to open our project in our terminal again back to the ruse and in one term in one tab you have to open two tabs open your open your project in two tabs in tab one you run pfgm PM running devs column node which runs the uh chain local chain in your other tab you run PM run Dev foreign this might take a while because it's generating a bunch of files and it's going to deploy to the local chain as well assuming everything goes well down here to play you can see a bunch of logs in the console so then we'll be good to go so we're going to wait until we until our contracts get deployed and now if I hit play I can see a bunch of logs in my console yep we have a bunch of logs in the console websocket client created syncing and these are all component updates now we know this works so the next thing I have to do is actually spawn a player into the game to that to do that first thing we have to do is associate unity game objects with entity keys from mud so open your tank prefab just by clicking it in the resources folder double click on tank and what you want to do is attach a player sync component to it and what player sync does is basically keep track of which key the game object has and whether or not it's a local player it's pretty simple so we'll say make sure change the save there and then we're going to create another empty game object in the hierarchy when this is the player manager and we're going to go into our scripts folder and drag the play around your script into the inspector on the right make sure it's attached to the player manager object and let's open that file so the first thing you'll see is that on start we get the instance of a network manager and when the network has been initialized we call this spawn function so in our spawn function what we have to do is first we're going to get the r burn wallet address from the network and Ranger and the next thing we'll do is we'll get the value of the current player from the player team thank you so you might be wondering like where does this player table actually come from so when we run pnpm run Dev in our project in the terminal you're actually Auto generating a bunch of these table definition files that give us really nice things like strong types and no subscriptions and querying crit interfacing with all like the low level UND networking stuff and then just do a one line call like this so we're going to say if the current player doesn't exist in other words in other words if we don't have an entry in the player table for our address we're going to spawn the player by calling a we're going to make a transaction to Swan player so if current player doesn't exist I'm going to call a function on the network manager called World sent and World send exposes something called TX execute which takes in a generic type that was set as font function spawn function comes from the auto-generated c-sharp bindings for our contract so this is like basically a C sharp version of whatever ABI was generated from your from your world systems and finally the last thing we want to do is subscribe to further updates from the player table uh it played so what this is doing is saying every time someone inserts a new record into the player table we're going to call this on update players function which we have commented out here also good practice is you want to properly dispose of your subscriptions so on on update players takes a player table update parameter this parameter is also Auto generated it gives you Keys table ID values and type by tuples from from like whatever update happened so in this case when you get the current value of the update so update the update type returns has has a tight value parameter which say Tuple first item for two boys the current value second item of the table is the previous five we only care about the current value here so let's say if if current value doesn't exist we're just going to bail out earlier because there's really not much for us to do there yet and then we're going to get the Polaris position from the position table so remember that in the contracts we set the player's entry in the position table to whatever X and Y they spawn at so we get that from the position table now we have to spawn Spawn from that position so thank you now that we know where we want to spawn we can actually spawn the player prefab so I'm going to say player I'm going to sell it to the result of an instantiate call which is we're going to instantiate the player prefab and we're going to instantiate it at the player's spawn point and we just wanted to have the identity rotation um next thing you want to do is just add this thing which basically helps with the camera and now I have to plug Unity which game launcher does this update key belong to so same as player that we newly instantiated their player sync component it's Chi is going to be equal to this key that we've just received from from the update and we're going to say if we updates key is the same as our burner wallet address then we will also say set the player sync local player key to this update key okay now we'll go back into our editor and we're going to wire up this script so all you have to do is go into resources and drag your tank prefab into into this slot over here and when we hit play we should see ourselves automatically spawn into the world and there we are and I can move around movement's not so now on chain so let's fix that so I'm going to open player controller script so first we want the player sync component and on start we want to get the current game objects player sync component so player is equal to gut employment and this time we want to subscribe to both record insert and record update events and it was in the position table so our subscription will be this and then we'll say our set our disposal to observe on Main thread and we're going to our column is going to be the on chain position update function so what do we just do basically what we're saying is every time something in the position table gets updated whether it's just the field which calls this or whether it's the whole row which calls this every time it's one of either one of those two happens we're going to call this column chain position update function and in here all we're doing is first we'll check to make sure the player being updated is also the player in the current game object if we don't do this then basically all game objects are going to uh change version every time every time it's like getting the update which we don't want we only care about the update for this specific game object and then we'll say if this is the local player where we turn early because we want to handle that that locally um if I undo this the player's position is going to update twice once locally when you move and again when position and smart contract updates and then we're going to get the value of this update which is like the new position they move to and they're going to set the destination to that new position that they moved to and in our update Loop we actually need to return early if it's not the local player as well now let's write a small function to actually send the move transaction it's going to be the same thing as like the spawn function before but we're going to use the move function type from our API bindings so it's going to be awake now network manager instance when we want worldsend.tx xq and this time instead of Spawn function is going to be loose function and thus takes an X and A Y for Rapid we see we're actually wrapping this in a unit task return type just because I think it's a little bit nicer than doing inside the code being sending a transactions is an async function unit doesn't really have a good native way to do a single weight unless you do code routines this is just a little bit cleaner and here so here we'll say send Booth transaction async and we want to make sure everything's of our proper type and you can see we have this yellow line that's one yes that like we need oh it's underweighted and we don't really care so it's safer care and then no more error just magically make that problem go away anyway if I hit play again in the immunity editor you can see that next time I move around you have a transaction event in the log as well so that means you're basically making the move transaction when you move so we have two more things to implement that's attacking health so we're going to start with attacking we're just only a couple lines in tank shooting in the file called tankshooting.

cs so first thing we're going to do is same thing as a new move function and call the attack function instead and then attack function takes an X and A Y location so you just as well and then when I left click over here I want to send our transaction well pretty much the same thing as what we did before now we're going to update our health when we get attacked so the first thing we need to do get the player sync component and this time we need two subscriptions we need two subscriptions we need a subscription for when the health changes and when the health gets deleted in other words when your player gets killed so our health updated subscription will look like this we're looking for the on record update observable in our health table which fires every time I record a row in the table updates and we're going to use callback with on health change function or deletion it's the same thing we're going to call this one else deleted and this time we want the on record delete and this callback will be on clear death so for the first one on F change we're going to say if the health changes the first thing we're going to do is drop a shell or a bomb above the player and that way people can see like what caused what caused their health go down so first thing we're going to do is we only care about the current game objects key and we want to initialize the our shell position at their that current a gay objects transform and we're going to put it a little bit up so we can actually like drop down and then we'll instantiate our shell prefab and we want this to point down so we're actually going to do quadrillion.look rotation back to the three dot down foreign as well so we're going to say the current value current health value is in the updates value the first one and we're going to set our game objects health to that value next thing we have to do is handle when your health row gets deleted in other words when someone erases your health again we only care about um our current our current key now let's just say if the updates value is null then we play the depth animation so the first if the first item in the value table is null the current value is null usually that means the key has been deleted in the table and in our case the players role in the health team has been deleted their debt so this should so let's go back to Unity again and this time I want to test that with multiple players um you can't so the way you have to do this in Union Fortune is I have to create a local build so I'm going to create I'm going to save this and create a local build and basically it's going to open up the game in a new window and then I have to play the game again in my editor at the same time so here is our first game and here I will also play it in the editor uh hopefully you can see that kind of and when I move on one side it updates on the other side as well same here and now if I for example want to attack if I'm this guy I want to attack this other guy I'll hold down e and just click on click on them and we'll have a shell drop and they'll be dead and they won't be dead but if we keep doing it they will be so let's spend a couple of minutes doing that because we're running out of time soon almost done and they're gone and now they no longer exist and if I'm back here I cannot control my player because my player doesn't exist anymore I'm dead so yeah that's it um um I will be around for the rest of this week as well so feel free to ask for any questions um in the Discord as well and yeah thank you cheers thank you learned sure there was a question from Marvin uh do you have to set the contract address in the network manager oh you do not if you are using this if you're using the template in the GitHub you don't because it automatically sets it for you okay and uh are there any known issues limitations within the union Library what kinds of community contributions would be most useful so right now the unit by Library does not integrate with lattices mode package so it's just reading events from the RPC so it might be a little bit slow it's not going to have a nice indexing features that mode has so that's one future potential feature you can add to the library as well and that's probably one of the most important things Nathaniel is another question uh can this system be incorporated with the unity game that is already in development I guess it depends on how like us how far along you are um but yeah I mean yeah so all you have to do is if you have a game that already exists you're gonna have to if you only have a client you're gonna have to put that client into the template into the package repository so you have access to contracts as well and then you just import the unit mud package from Unity so yes foreign well there are no other questions in the queue we are at the top of the hour so thank you again I learned her for the presentation workshop and thank you all for participating in the event as well and um this is our last workshop for for autonomous worlds and don't forget about the project you back session tomorrow and uh good luck with the rest of packing have a great Friday and uh have a good weekend oh it's all right uh there was one other question does that already have support for something like an ethereum or do we need to add this ourselves so the unit mud package is already in GitHub it's open source and it actually uses an ethereum on the back end as well so so the answer is yes it does have support for ethereum great well cheers everybody and yeah have a good Friday and uh have a good weekend foreign

Automatic transcript — names and jargon may be misspelled.