Hi this is mccity for a new episode of my boarding tutorial and i’m going to implement a mana system in this tutorial so in the top left corner you can see two numbers the second one is how much mana is in a chunk so that’s something that we will Generate and keep in the chunk and the left number is how much mana the player has collected and i made it so keybinds that there’s a key binding yeah tutorial keys gather mana and it’s set to dot by default so if i press that you can see that the mana for the chunk Decreases until it’s empty and we have to go to another chunk to collect more mana so that’s basically what we will implement this tutorial in the next tutorial we will actually make items and stuff that uses mana so yeah let’s get on to it so to make this mana system system we will Use data that is attached to the world where we store the mana available in the world for chunk and we will also need data that is stored with the player like how much mana is the player already gathered so we start by making a new package nana system and in that package We will set up three different sub packages clients data and network so first let’s start with client and on the client system on the client side we actually want to have key input so when we press our dot key we want something to happen so let’s copy two things here i will Explain them so key bindings is where you define how the keys which keys your mod supports so we make a gather key mapping getter mana key mapping which is new key mapping with this key which is used for the language file you specify where the key will be used In game so there are some other possibilities here universal only in gui or in-game we want to engage we want this as the default key and this is the category which is also also a language key that is translated and then we say register this key binding We have to call this from somewhere and we will call that in here oh not here the bindings in it because if you go check this you can see that it’s synchronized so that means we don’t have to use this put this in here we can put it safely in here It’s red safe okay so this defines the keys but now we need to be able to listen to when that key happens for that we have an input handler so basically what we do here whenever a key input event occurs so when the player presses a key that’s an event That occurs client site you go check it out this event device when the keyboard input is detected we check if our key mapping is consumed and if so we will send a packet to the server because mana gathering has to be done on the server so we have to define this but let’s First register this one that’s also inclined setup and for that we add a listener okay so we add listener for this event on the client so we are in client setup and we add this to the forge bus so two steps for key bindings first define the key keybinding itself then Make an input handler for it you also fix the language provider and add two key to languages like this so that’s the default english translation for these keys that’s why it looked nice in the in the game okay so now we need networking we need to descend A message to the server that we clicked that user the player clicked together mana key mapping or together so first in setup we make our messages class which is the main class for networking okay and yeah let’s do some things here so basically we make use of simple channel which is Something that forge added it’s a easy way uh to make a network channel between the server and the client for your mod so we make a new channel there’s a channel builder we give it this name a network protocol and we actually don’t use here you could check if The server side of your mod is compatible with the client side using this you can for example make sure that you have a mod that works with all the versions on the server as well but the client can be updated or you can make sure that it has to be exactly this Same version that’s up to you how you use it i generally leave it as this because typically mods are the same version anyway okay so we have to call this register somewhere and that’s done in mod setup right here say again i believe this is from forge and all four stings are automatically Yeah synchronized but you can’t actually see that here yeah it it uses locks but things for forge are typically okay to use like this okay so this initializes our channel that we can use to send messages from the client to the server and the other way around now we need to define Or actually our actual packet and we will put that here in network let’s copy it and explain what it does yeah we don’t have a mana manager yet so let’s put that in comments for now okay so this is a simple message it has no data we just want to tell the server That the user pressed the key so it doesn’t contain any data that’s why this is empty and this is empty in this tutorial we also get a message where we do have data then i will explain this more the reason it’s still here it’s because it makes it slightly easier to register and Yeah that’s why i do that like this then we have handle this is actually called when the packet is received on the server so it gets a supplier of a network context you get the actual network context and then this is important as soon as you receive the message you You use and you work to ensure that you are on the correct threat because otherwise here you are in the networking threat and it’s not allowed to do for example things like getting a block entity or accessing the world here you should do that in here that’s why there’s always this And it will make sure that this code is executed in the correct thread and then you return true to say to the system that the message was handled correctly we also need to register this and that’s done like this okay so to our simple channel we create a message builder This is the class of a message this is an id which is just a number that keeps increasing and we say it’s from client to server it’s a message that goes to server this is the decoder which is just this constructor it doesn’t have to do anything really This converts that’s the encoder it converts the packet to bytes and again it doesn’t do anything for this particular example and this is the mess the thing that will handle the message we also added convenience function this is just so that we can keep this private we have a sent to server here With a message note that messages don’t implement or extend anything you can every class can be a message and that’s why it’s done like this using genetics okay all right so this is uh basically it oh yeah we also need yeah we’ll do that in a moment but Our message doesn’t do anything yet because we don’t have the manage system ready i will do that in a moment so basically let’s put this back what do we want to do whenever the player presses this key client side we send a message to the server And on the server what do we want to do there we want to get the mana that is present in the chunk which will be we will do that in a mana manager we extract mana at the position that the player is if there is no mana to be extracted we say We send the message to the player which will come as an error message translatable component message no mana with style in red and this is to indicate that to the current player um is there a comment with it no there’s no comment with it okay if there’s mana if extracted is greater Then we will add the mana to the player cape using capabilities so here you see this uses world data this uses player data and we will expand on this in this tutorial first let’s add some language keys or this like this okay so mana manager uh will store the mana in the world So let’s make a class called mana manager and to store something in the world what i like best is to use this extend safe data from minecraft this is something that you can use to attach data to a dimension to a world okay let’s copy some code so we need a constructor And we need another constructor yeah that doesn’t work okay what’s the problem here yeah we just need okay so basically we extend safe data and we make a public static method to get that data from the current level this only works of sight so for that reason we added a protection here so That if we ever try to do this client side we will get an error otherwise we cast the server the level to serve level we know we are server side and we get the data storage for this dimension and then we do compute if absent and the first This parameter is a function that converts compound tag to mana manager so that will be this constructor so basically we read from this is used if the mana system is already saved in the in this dimension if it doesn’t exist yet then we use the supplier manager which Will be this constructor so yeah if you know generics you know this but the this is not the same as this because this corresponds to this constructor and this corresponds to this constructor so that’s important to note and then you give it a name so this line makes sure that if the mana System is not present then this constructor will get called and it will be added to the data storage if it is present then this constructor will be called and it will be loaded from the level data okay so yeah and we want this data to be birth dimension Okay so that’s uh because if you want really global data global that’s over the entire uh server then you can access your data on the overworld because the overworld is always there you can always add data to that that’s for really global data but in our case We want this to be per dimension so what do we want to store per dimension we want to store how much mana is still left in every chunk so let’s first make a very simple class which is the mana class it’s just a class that contains one Integer a constructor a getter and etc nothing more that’s very easy and then we make a map which maps chunks positions so that’s a class from vanilla which has a chunk coordinate to mana so for every chunk we store mana it’s initially empty though we also need to load And to save this so let’s get some code for that first to save we use this so basically we need to save the mana for every chunk so we need to make a list so we start with list and we add that list to the main tag and then for each This will be let’s give it a better name junk boss and this is called mana so for every mana instance that we have in our map we make a new compound tag we store the x value the set value and the mana value And we add it to the list so this is how we save our data to load it we have this code so we get the list from the tag with this name the elements of the list this list are of that type to their components compounds we iterate over the list we cast We create our mana instance we create our chunk boss and we put it on the mana map so this basically solves loading and saving okay let’s add a simple helper get mana internal also we need random hold on i will explain this so basically oh yeah we have configuration um This function which we will use in a moment to get the mana instance at a given position so first we convert to position to a chunk position and then we do again compute if absent so we try to see if we already have mana at this given position if so we will Return that otherwise we will make a new mana instance with random mana in it okay so let’s add the mana configuration as well mana config here it’s a server side config and we have a chunk minimum mana junk maximum mana and let’s add that so we have new config config for our Mana system okay so this is how we populate our chunks in a lazy way we don’t pre-generate this but every time a position for a new chunk will try to get the mana we will generate a new mana for that chunk randomly okay um We need a way to get the manner at a certain position a public way so public int get manner we call get mana internal and we return the mana at that position we know we can do this safely because this will always return something it’s not null And we need a way to extract manner okay given position we get the mana eternal we see how much mana is present if it’s greater than zero we decrease it this is important we mark it set 30 if you don’t do this then our safe will not get called when The world is saved so you have to whenever you make a change that needs to be saved here you must call set 30 and then you candle so normally exact mana works here now so basically this line first we get the mana manager for this level we extract mana from it and This will automatically modify the mana in the level and then we will add it to the player so let’s do that now first let’s add the player mana class oh i wanted to add it i accidentally pressed cancel so again this is like a bit like the mana class it also Holds the mana int it has a setter it also has a add mana a little bit easier and then i will explain this later but it also has a way to save and load itself save nbt data load mbt data and it just stores the end for the mana That’s very easy so this data is what we will store with the player how do you do that that is the easiest way to do that is using capabilities and for that we have a player mana provider and this will require some explanation so this is capability provider and it’s also serializable So basically this means this is a class that you go check here it implements cat capability so that we can get our capability and it implements serialize and dc realize here we define our actual capability so we have a capability of capability player mana so that means That this is the data that we want to store with the player we give it a name and then this line doesn’t really matter but this is what you have to do to actually initialize this in our player mana provider we have a player mana and a lazy optional for get capability so Remember in our block entity tutorial there will you also used capabilities for forge energy and for items and use click lazy options to store to store the mana to store the capability and this is the supplier create player mana which will use the cached player mana that belongs with this provider Play manage new player mana and this will then be stored in the optional we implement get capability and the cited version is exactly the same and then serialize and dc realize we call we to create player mana and we do the safe npt or the load npd data okay Now to make this actually work there’s a bit more magic that we need let’s copy a class and then explain what happens here in this class we have various events that can occur where we need to manipulate the capability for the player so first there’s attach capabilities event this event allows you to Attach capabilities to something in our case we want to attach capability to a player so that’s and a player is an entity so that’s why we use this but you can also use this to add touch capabilities to block entities or to Other things to chunks for example this for example for block entity you would typically only do this when you want to attach a capability to a block entity that you don’t own yourself so and also you don’t own the player the player is something from vanilla so that’s why you need this event So if our object is instance of player we check if the player mana is already present and if not we do add capability let’s actually called it player mana and we attach our player provider to it so that’s how you add a capability to to the system but there are other important things Uh attach a player capability to the player i mean when the player is cloned so this occurs caused by death or by traveling from the end to the overworld for some weird reason when you travel from the end to the overworld the player actually dies and then you lose all capabilities just Like that player loses all items and to fix that you need if the event was death you need to copy the player mana from the alt from the original player to the new player and that’s why we needed to copy from so to that we can copy the mana so that The mana is not lost if you want you could implement a system here where mana for example you lose 10 percent of the mana if you die you could do that here that’s something that you that’s up to you we also need to register so here we attach the capability to the Player but we also need to register our capability so we basically need to register player mana as a class that is or uh our capability that we want to to support okay yeah and this uh i will explain in a moment that’s for later so these we need to uh subscribe to these Let’s do that first also this yeah okay we need to do some imports okay so this will now work uh let’s explain that first we get the mana capability from player and if that’s present we add the mana that we extracted from the player this should normally always Be the case because we make sure that the player has the capability all right so basically to register our three new functions we need to do this so add listener on player cloned that’s for this one add listener on registers capabilities this one is special special because it’s An event that has generics you actually need to use add generic listeners with the class for which this is meant to be used okay okay so remember let’s remember that we showed our mana in the top left corner to do that we need our mana back on the client So we started from the client when the player presses the dot key but the rest of this processing all this is served side so the client doesn’t know what the mana is in a chunk and the client doesn’t know what the mana is on the player so we need to communicate That to the player and we do that on a regular basis so that’s why this is important so let’s first we will yeah okay let’s explain this uh worlds ever so levels or worlds have a dick every tick they every world will get a tick We don’t want to take client side and we only want to tick at one of the two phases so there’s a start and end phase otherwise we will we would take it twice every 20 20 times per second then we get the mana measure for that world and we call tick On that which is not implemented yet let’s do that i actually want to put it in here so what do we want to do here here we want to make sure that every every time that the data is synced to every player in this level so that that player can show it In the hud alright so how do we do that let’s copy some code and we need a few variables we want to we don’t we don’t want to send uh we don’t want to send uh this to every client every tick so we have we do this twice per second that’s fast enough Um there is here a possible expansion keep the previous data so i’m not going to do that but you can in principle keep the previous data that was sent to the player and only sent if changed that would be an optimization and so and another expansion here is to Slowly regenerate mana in chunks but i will also not do that that’s things that easy to do by yourself but basically what we want to do for every level every 10 uh two times per second we check all players for each player we check if it’s survey player that will Always be the case we get the player mana and we get yeah we get the player mana from it and we get chunk mana so junk mana will use this and player mana will use the capability system and we want to send that to the player using a new package Which will go the other way so this is a packet that goes from server to client yeah we need to fix that this is a packet that does have data because we want to send these two integers to the client so that’s a constructor this is the constructor that reads these two values From our byte buffer and this is the method that will serialize it to the byte buffer okay let’s first register that okay so basically we have a new message it goes to the client this time and that’s how we do this we also need a new convenience function to send to player So here we use instance.send packet distributor player with the given player that’s how you can send to one player there also you can send to all players but we don’t want to do that because every player can be in a different chunk and has different mana so we need to target Every player individually okay so that should fix this okay so this works now but we need to store our player data right side like this this is simple class that holds the mana that was received from the server it’s static because yeah client side you are alone there’s only one player That’s you client side so we you can keep that in a static variable that’s okay so one important note here this is a packet that goes from server to client so this class has to be available server side as well as client side but that means that you cannot use things here For example it would be illegal to do things like this here you can’t do that here because this is a client-side class you can see that because it’s annotated with this by the way never use this for yourself it’s not needed this is purely meant for minecraft for forge it’s An ugly hack you shouldn’t use it but you can if this is present on a class you know that it’s only available client side so it’s not safe to use that here because that would mean that this entire class can’t be class loaded on the server So to do that it’s always a good idea to put actual client code in a different class so that’s why we do that here all right so basically we’re almost there so we have our two packets so we have the thing to send from client to server we have Our mana manager which sends data back from server to client and the final thing that we need to do is actually implement the overlay so let’s do that so there’s a very nice new system in forge which is in game overlay basically you define an overlay which is Just a simple interface that you implement that has these parameters and in that you can do your hui stuff in this case we get from client mana data the player mana the junk and we draw it on screen on this location ideally you would make this configurable And we will do that in a moment but basically that’s how you can do this you need to register this overlay and to do that we go to the client setup because this is client side and we add this so overlay registry so we do that in init register overlay above hotbar element So we want to register above the hot it does not uh the position above the hotbar but in what order it will be rendered yeah we give it a name i’m not sure what that’s used it’s not actually showing and then our game overlay so that’s very easy Very easy way to make a hut let’s add some config for it as well so that you can configure the position where this is stored three values and resistor client configs okay um and then i had x x location of the mana default is 10 yeah okay that’s fine Actually you could set the min value of minus one and then you can say if it’s minus one you disable that let’s do that that’s even friendlier default value all values are allowed here so this is basically white everything set at maximum we need to call this like this okay And then we actually need to over to use this and also we need to test let’s do so if x and a like this okay let’s try it out see what happens now okay yeah there was already an error i think intellij is a bit confused let’s start it again Okay this is better for some reason it was a bit confused okay all right so apparently for some reason okay so the hut is showing let’s see what’s wrong let’s do some debugging oh yeah i forgot to generate the thing that’s why this is not working but there are some other things not Working so let’s try to find out so let’s go to creative let’s find out what’s wrong so let’s do some debugging that’s actually pretty useful so i probably forgot something so let’s first start with the keybinding um input ender let’s set a breakpoint here and see if we get to that point We do okay so that means that this is at least dom let’s get here and set the breakpoint here okay he also gets here so i pressed continue extracted we extracted one so that’s okay and actually so we did get some mana from the level so that means Did we forget to do something let me check mana events is this actually called no that’s not called so that’s our problem and i know why i forgot to add the listener for that okay let’s go back so using breakpoints is an easy way to find out if something is wrong or not Or where the problem is all right let’s see if it works better now yeah but it’s in the way you can’t see it i could of course move the top interface but let’s try and see if we can i don’t know if this will work at runtime yeah it works at runtime so Let’s go to chunk that has almost no mana so not this oh this is slow okay let’s check that our message works correctly yeah okay we need to fix the translations so for that to be called rendata okay so normally yeah this these two and this one is now correct So that basically concludes this tutorial in the next tutorial we will you add some items and some rendering to make this more fancy but this is the basic mana system so see you next time bye bye Video Information
This video, titled ‘Minecraft Forge 1.18.1 Modding Tutorials (7): World Data, Player Capabilities, Networking, Overlay’, was uploaded by Jorrit Tyberghein on 2022-02-19 07:37:38. It has garnered 5042 views and 88 likes. The duration of the video is 00:45:02 or 2702 seconds.
This is a modding tutorial series for Minecraft 1.18.1 with Forge. Check the wiki for more information: https://wiki.mcjty.eu/modding/index.php?title=YouTube-Tutorials-18
Table of Contents:
0:00 – Introduction 2:40 – Key Bindings 6:20 – Networking 14:05 – Mana Manager: Saved Data 20:10 – Mana Configuration 22:20 – Player Mana: Capability 25:20 – Capability Events 31:20 – Sending back to Client 36:20 – Mana HUD (overlay) 41:30 – Fixing bugs