14. Simple way to create UE MMO inventory with Java server

In the previous post, I covered the implementation of the back-end Java server work for a basic inventory system.

Therefore in this chapter, we will be looking at the steps required to integrate it in Unreal Engine.

Here’s a video going through the high level implementation as well as a demo of the results.

Also I uploaded the example project used here.

Unlike some of the other posts, I tried to make everything in Blueprints this time round, incase this is easier for people. It does however rely on free plugin called VaRest.

This video is not focusing on the aesthetics, but rather the data flow between systems and storage. Doing so, the approach is generic and can be tweaked by people as required.

Simple inventory UI and items dropped on the ground

Overview

Let’s begin with what components do we need to work on and why

  • Inventory Widget
  • Inventory Item Widget
  • Game Mode changes
  • Player character changes
  • Utilities and helpers

The inventory widget should be self explanatory. We want to create a widget component which will contain a dynamic number of inventory slots which can be populated with items or remain blank.

The Inventory Item widget is a small component which represents the slot for an item in an inventory. You’re able to give it functionality in future, such as right click equip, drop etc. In this example we will just drop the item on click event.

Game mode changes will have us store some world information here – i.e. dropped items on ground floor. We can store it on player controller blueprint, but I think it may be better inside game mode as it may allow easier interactions if other NPCs or mobs were to interact with those world items.

Player character changes – this will refer to us opening inventory which is tiny piece and also capability to pick up nearby items.

Utilities and helpers are blueprints to help with passing data between blueprints and serialize data.

Let’s cover each topic one by one.

Inventory Slot Widget

Inventory Slot widget

As you can see, I made this as a tiny 60x60 widget component. It contains a SizeBox, Overlay, Iamge Component, Text component and Button.

At this time, mainly just the image component and the button is utilised.

Let’s have a look at the construct for this component, to see how we populate the image for the item.

Construct for the inventory item widget

I added one extra bit to the response of item, which is the Item Config. It contains two pieces of information, only one of which I am utilizing right now – icon. Essentially when I create a ‘item’ component in my server, I specify the location of the image I want to use.

I can evaluate this in other ways, for instance using a Map in a helper file and getting the key using Item ID – we will look at this when we spawn actor.

So now if we have file path for the icon, we can simply import it using the file name and apply the image to the image component.

Dropping the item

The next piece of code that we look at is ‘on button clicked’ – we want to drop the item when the user clicks this button.

First, let’s recall the Postman request that we made in the previous post.

Postman drop item request

This gives us the Json structure that we want to create.

The most complicated part of that is getting the character location, which is not too hard – we can GetPlayerCharacter and with that, GetActorLocation. This gives us the vector location which we can break and insert into the location structure. The Map field is not used currently, so we can keep the consistent map1 that we were testing with.

See the blueprint implementation below, which uses VaRest plugin for handling the API calls.

On button click, drop item request

Inventory Widget

The next thing that we’ll look at is the inventory widget.

Simple UI widget for an inventory representation

This is a very simple component which has a canvas panel just around the right corner for an inventory.

It has a image field – it allows you to put whatever design you like for the background of this inventory system. I just tinted the color slightly for it to be visible.

The next piece is a Uniform Grid Panel which is an important component.

My initial inventory design was to have a simple 10×10 inventory (extendable), so I was looking for square design. Consider making dynamic as you like (e.g. scrollable etc.).

The inventory item components are added dynamically, hence you don’t see them here in this design. This allows it to be extensible.

Inventory Blueprints

The blueprints are relaively large so I will split them into smaller sections and describe their intentions.

Construct the inventory widget – prepare requests to fetch inventory

In this part, we create a timer to fetch user inventory. I create an event which will not be this fast in production. The 0.5 seconds is only for demonstration purposes. i.e. it can be set to something like 10 seconds for re-consolidation purposes (incase it goes wrong somewhere else).

In reality, you should have this event Get Inventory Event called whenever there was an inventory action, e.g. item picked up, consumed, etc. This way you can greatly reduce load to server.

Now looking at the actual request, here’s the postman request that we wanted to mimick:

Get inventory request

The request itself is straightforward and easy – no url parameter, just adding the characterName to header.

On the other hand, the response is complicated, but we will abstract this into a helper method to keep our blueprints more clean. We will cover this part in chapter below.

The next connecting part of this blueprint is:

Connecting part of blueprint, collecting result data

Here, we get the array field using VaRest function – this is in format of VaRest Json Object which we cannot directly work with. Therefore we want to iterate over this and convert it to CharacterItem. This function will be implemented in one of our helper methods.

You will also notice that when i am collecting, I am adding this to a CharacterItemsMapTemp. This is a local variable containing the CharacterItems mapped by their location as the key. This is quite unusual, but it will boost our performance.

List of variables used in Inventory Widget

Notice that the variable type is set to Location2D Structure and Character Item Structure. We will generate those soon.

The next part of blueprint is complicated – to be honest it wouldn’t look so complicated in code, but there’s a lot of small functions required from blueprints which make it appear inflated.

Populate items in inventory blueprint

First let’s describe the intention behind this, then we’ll look at the code.

The intention is to receive a list of items and only update the delta of those items. i.e. you don’t want to destroy all items in inventory and reconstruct. You want to evaluate what’s the difference between what you’ve received and what you have and action only the diff.

For example from last state, your inventory items had:

  • Item A
  • Item B

in the new response you got

  • Item A
  • Item C

Therefore you know that:

  • don’t touch Item A
  • delete Item B
  • add Item C

Let’s talk about what its doing in pseudocode.

  • we just populated CharacterItemsMapTemp so we iterate over each key in this map
  • for each key, check if the CharacterItemsMap contains this entry
  • if it exists in CharacterItemsMap – remove it from there (don’t touch it in UI basically)
  • if it doesn’t exist in that list, create inventory slot widget for it
  • populate the inventory slot widget with data required by constructor
  • add this widget reference to a widget list variable, mapped by the key from 2nd step
  • add this widget to uniform grid, extract the row and column info from item server data
  • When you complete 2nd step loop, iterate over the remainder Character Items Map
  • This list should have only items which were not present in response – they need to be deleted
  • For each one, find the item in the widget list added in step 6, and remove from parent.

That’s it for the inventory widget, let’s look at the models and helpers that we needed to use in the previous steps.

Models and Helpers

In this part we will cover the models and helpers required by our blueprints. Generally its to share data between the blueprints and extract them from the VaRest (or other API) plugins.

Models created

These models are simple structures, so to create one, right click -> Blueprints -> Structure.

How to create Structure

These structures are just reflections of the models we used in our Java server code – so just have them as the same as your requirements if you’ve got different data.

Model example in Java

The structure in UE can contain basic values, or other structures (nested).

Item structure in UE

So for example, we can see tags are another user defined structure, which is array. This mimics the image above List<Tag> field in Java.

And the Tag structure in UE is just:

Tag structure

As you can see its simple the name/value String pair.

So just create all the models that you expect to use. For each one, we’ll have to create serializes or translators essentially from JSON -> Struct and vice versa in some cases.

That’s covered by our Helpers:

Our Helpers for JSON translation

In order to create one of these right click -> Blueprints -> Blueprint Function Library.

How to create a blueprint function library

Here’s the example for VaRestToStruct looking at probably the most complex one, Convert to Item function.

Convert to Item helper method

As you can see, you have to define an Input and Outputs for the function. All of the inputs for these function will be Va Rest Json Object fields. The outputs will be whatever you’re translating, so in this case Item Structure.

With the Va Rest Json Object you can do things like Get String Field, Get Array Field, Get Number Field etc. This is basically like any other Json parser. Generally speaking you will use JSON almost always with networking so if you’re not familiar with them, you should check some tutorials on them, they will be super useful in future.

Inside this function you’re also able to nest other calls, for example you can see we have Get Array Field with Field name: "tags". We translate this using Convert to tag which has the blueprints of:

Converting array JSON to tags

Struct to VA Rest

This function library will help us take IN the structure and convert it to URL string param, or Va Rest (JSON) body for the API calls.

For example, in order to call Get Nearby Items we have a GET request with url encoded location parameter. Therefore we want this as a string in form of ?map=<map>&x=<x>&y=<y>&z=<z>.

Location to URL Encoded string

That’s what this function achieves – it takes in Location structure as input and provides a encoded String output.

The second function is a bit more complex, we’re constructing the Drop Request object.

For reference here’s what we’re trying to create in postman:

Drop item request JSON example

Here’s the blueprints of how we achieve this:

Drop request to JSON part 1
Drop request to JSON part 2

And above is how we can convert the structures into the JSON objects. Simply going field by field and populating the desired values.

Item Actor Resolver

In order to drop an item and see it, we need to evaluate which class to draw on the map. That’s what the Item Actor Resolver is going to be used as. Before that though, we should create some actors for our objects.

In order to keep all assets generic and free, I used Craft Resources Icons pack and the Infinity Blade Weapons pack.

Obviously the icon will NOT match the blade pack, but you can use your own ones as desired – we’re focusing on the approach rather than aesthetics here.

For the mesh, I decided to go with SK_Blunt_Cinderblock mesh – feel free to use whichever mesh you like.

Chosen mesh for an item

Now you can right click in a desired folder (I chose Inventory/ItemActors) click to create Blueprint Class and select Actor.

Create new Actor blueprint

With the new class add a new component for skeletal mesh and add the mesh for the chosen item, highlighted in the image. Then just rotate and position the item as you like.

Populating the new actor to represent your dropped item

Of course you can make additional modifications here as you like, for instance making it a spinning component. But we will keep things basic for now.

With this actor item created, you can generate the item actor resolver. This class will determine what actor to spawn on map depending on the item ID (or another field of choice, but should be unique).

Item Actor resolver

As you can see, this function is very simple. It takes in an Item ID and checks the Map To Actor Map. You need to populate the default values here, so for each ID of item that you have, select the Actor reference.

Note the variable type here, its a Map where the key is String and the value is Actor class reference.

Game Mode changes – populate dropped items on map

As described in initial summary, we will populate the dropped items on map using the Game Mode.

It doesn’t have to be here, it can live in the Character Controller for example, so feel free to move as you like.

Handle Dropped items part 1

Here we see that we have a timer, every 0.5 seconds we check what items are near to our character. We do this by creating a GET request, getting the players Actor location and generating a Location Structure using this data. We then use the Location to String helper function created in our Helper methods.

Handle Dropped items part 2

We use a similar technique to our inventory widget of keeping a Map of nearby items. We have a temp map to keep those values for processing. After we populate the temp map, we call our Draw Dropped Items On Map event.

Handle Dropped items part 3
Handle Dropped items part 4

In this blueprint, we iterate over each of the temp items, check t o see whether we need to add or remove this item from screen.

If we need to add it to screen, we get the location of the dropped item and use the Resolve Item Actor method we covered in chapter above to get the class of the object we want to spawn.

We also keep track of the spawned items using the SpawnedItemsOnMap variable.

If we need to destroy the object, we locate it from the SpawnedItemsOnMap and call the DrestroyActor method.

We then set the NearbyItems to the temp that we received from the response.

The blueprints make it look quite complicated and to be fair it can be tricky to get your head around, but when you break down the logic its not so bad.

Again its more efficient doing it this way as you don’t want to make UE re-render all objects for each request, as that would take up a lot of processing power.

One key thing is that you should set NearbyItems to public variable so that your character controller can access it, we will use it in next step.

Make Nearby Items public accessible

Character controller – pick up items and open inventory

We’ll start off with the easy one, display the inventory:

Show inventory on button press

There’s multiple ways of doing this (you could map an engine input for instance) but here’s a simple way of opening/closing inventory on button I press.

Simply set the visibility of your widget from Visible <-> Hidden.

Next, we will want to create a function of finding nearby item to player

Get nearby item ID

In this function (add new function using the UI on left side) we get the game mode and get the Nearby Items that we made public in the last chapter.

We just want to return 1 item, so we just check the length of this array, if greater than 0, it means we found the item and simply get the 0th index of that array and return it.

For next part, I created clean new graph on the character controller for the pickup item logic.

Pickup nearby item logic

I made the logic such that when you press the space key, we get the nearby item id and if an item is found, we prepare a request to pick it up.

Here’s the postman example for that request:

Postman example for pickup item request

As you can see, the request object is simply the droppedItemId.

We don’t actually need to do anything with the response as our inventory module is set to self refresh however, you should make a callback to inventory module here to manually refresh after getting a response from this API. It would make this more efficient.

Summary

That’s it! You’re now able to walk around the map as well as:

  • open inventory with dynamic slots
  • pickup items
  • drop items
  • see them populated on the map as actors

What optimizations can we make?

For the API to get items around the map, we call this method quite regular, 0.5 seconds each time.

This makes it appear smoother. For such a high update request, its better to setup a socket connection instead of standard HTTP request.

In future we will look at those and potentially explore equipping items or consuming them etc.

Best of luck!

2 Comments

Comments are closed