Tutorial: Solar Panel
The theme of the 4th modding tutorial competition was to create a mod for "Space Day", which celebrates science and technology. In keeping with that theme RedDwarf (myself) and Pleasure have teamed up to build a working solar panel for ARK, completely from scratch. Pleasure created an excellent youtube video tutorial in which he shows how the solar panel model was constructed. And this tutorial that you're reading now will walk you through how to setup the solar panel so that it can be used in-game.
Click Here to watch the modeling tutorial by Pleasure!
This solar panel will provide power during the day, as long as it's located outside.
Additionally, the player can build batteries inside the solar panel's inventory, which allows the panel to charge the batteries during the day and discharge the batteries at night when no sunlight is available. Each battery extends the solar panel's power by 1 additional in-game hour. Players will need to build enough batteries to survive the night, if they want uninterrupted power.
The charging methodology is vary simple: When night sets, the solar panel will count the number of batteries currently in it's inventory, and begin a countdown showing how much battery time is left. Any battery added during the daytime is considered charged when night sets, but any batteries added at night will be ignored (since they have not been charged by sunlight). Additionally, if batteries are removed at night, the timer will go down -- and if it hits zero, the solar panel will be out of juice and shut down until the sun rises the following morning. =)
Let's get started!
Setting up the Solar Panel structure
Firstly, create a new directory under your "Mods" folder called "SpaceDay_SolarPanel" (or whatever you'd like your mod to be called), and create a new PrimalGameData file for it.
Inside this mod folder, I usually create an "Assets" folder for sounds and meshes, and an "Items" folder for blueprints and in-game items.
Like many modders, when creating a simple crafting structure, let's start by copying the Smithy ("StorageBox_AnvilBench") to our "Items" folder, and rename it "SolarPanel_BP".
Now, before we begin, let's discuss a little trick that we're going to do. If you look at the reference picture at the top of the tutorial, you'll see that the solar panel is connected to the battery storage box by an electrical cable and junction box.
Wouldn't it be nice if that electrical cable changed color when the power was on, as a visual indicator? We can do that! The devkit has an easy built-in way to change materials on it's default static mesh when the structure is activated. For example, a refrigerators green lights might come on, etc.
So what we're going to do is assign the static mesh of our solar panel to be that cable (so that we can change it's color on activation), and we'll manually add the actual solar panel later as an additional static mesh component. Your "components" list will end up looking like this:
More on that later!
Next, let's take a look at how we should setup the "SolarPanel_BP" defaults.
Solar Panel: Defaults
As mentioned earlier, we're going to use an electrical cable mesh as the primary mesh for this solar panel, so that we can easily adjust it's materials when the solar panel is powered up, like so:
- Active/Inactive Materials: Powered and unpowered cable materials (yellow vs. gray).
- Disable Activation Underwater: Probably a good idea for players to not put their battery boxes underwater!
- Powered Water Source when Active: This means that the structure will generate Power and Water when activated. We're only going to add snap points for electrical cables, but in theory you could also get water out of this structure if it had a snap-point to add water pipes. That doesn't sound safe!
- Container Activated/Deactivated Sound: For this, I borrowed the pre-existing activation sounds from Aberration's Charge Lantern. This adds a nice mechanical sound to the structure when it turns on.
- Dont Actually Snap Just Placement: The generator blueprint has this checked, so I'm following along. I believe this means that the structure cannot use existing electrical cables as "support".
- Blueprint Draw HUD: Later we will be adding code to generate a nice "Status" message for the user when they look at the structure, so we'll need this box checked so that the graph function will be called.
- Damage Type Adjusters: This structure doesn't take any special damage from anything.
- Structure Settings Class: "Broken By Metal" is the "Wood Tier", meaning that you can break it with metal tools, which makes sense for a solar panel. This is also in keeping with the durability of the generator.
- Consumes Primal Item: This should be setup to consume the PrimalItem that represents your SolarPanel_BP blueprint (we'll cover that in a moment).
- Structure Snap Type Flags: This one is very important. This number serves as a bit-mask to tell the game which types of items can be snapped to it. For the full details, check out the Snap Points page.
- Snap Points: The structure contains 4 snap-points, which are all identical except that their "Point Rot Offset" is rotated by 90 degrees each time. This allows you to snap cables in 4 directions. These cables have a "Point Loc Offset" which puts the cable snap point just under the battery box at the same height as a generator's snap point, for consistency's sake.
Next, we setup the placement details, health, name etc:
- Placement Encroachment Check Offset / Box Extent / Trace Scale: These settings determine how much space your structure will need in order to be placed.
- Placement Rotation Offset: This rotates the model 90 degrees so that it's facing us when we place it.
- Requires Placement on Structure Floors: Due to the shape of the model, it would look very bad if placed on uneven ground, so this solar panel requires placement on a structure.
- Placement Choose Rotation: Allow the player to rotate the structure.
- Snap Requires Placement on Ground: The solar panel should always be on the ground.
The remaining settings are default for a generator. The "Destroyed Mesh" is left empty, because destroyed meshes take up a lot of disk space and inflate the mod's size, so that's left off for most of the mods that I create.
Solar Panel: Components
As mentioned previously, your SolarPanel_BP structure will contain the following components:
- MyStaticMesh: "SM_CablesStraight" (The main mesh for the structure.)
- JunctionBox: "SM_JuctionBox" (This is purely aesthetic, to show how power would get to the battery box.)
- SolarPanel: "Solar_final" (This is the excellent solar panel model that Pleasant made for this tutorial.)
- ActivatedEmitter: "SolarPanelEmitter" (This is a copy of the ActivatedEmitter from the Generator, modified with a free sound loop from [FreeSound.org], which gives it an electrical buzz sound when activated.)
These components can be positioned however you like. I put the sound emitter in the middle of the battery box, and I aligned/scaled all of the meshes until it looked right to me. But the sky is the limit, you can add whatever you want. Be careful not to go too crazy -- adding components this way will increase the load on the users GPU more than a properly rendered single static mesh, so use these components sparingly if you can.
Setup the Primal Items
Before we go any further, let's setup the PrimalItems that we'll need later. Primal Item's are blueprints that describe the item as it exists in your inventories, whereas structure blueprints define what is actually placed/built in the 3D world.
Let's start with the Solar Panel. Create a new blueprint called "PrimalItemStructure_SolarPanel" that's parented to "Primal Item Structure Generic", and change the following defaults:
These settings just change the name of the item, the icon, crafting requirements, the structure to build, and which folder the engram will show up in.
Feel free to adjust these values as desired!
Next, let's create the PrimalItem for the battery that players will be able to craft in the solar panel. Again, not very complicated -- just a simple item that has a good name/description/icon, and weight/crafting-requirements that make sense based on the context of the item.
I made the battery cost a little high, since they completely replace gasoline, and you only have to build them once.
Setting up the Solar Panel logic
Buckle up, kids! We're about to go diving into all of the logic that makes the solar panel actually function. Don't worry, it's not too bad. =)
Open up your "SolarPanel_BP" blueprint, and click on "Graph" on the top-right. Then click the "Event Graph" tab.
Let's start here.
Like most "Event Begin Play" events, we start with a small delay to give the code time to initialize everything. In many cases (but not all) this is considered a general best-practice in order to avoid problematic glitches down the road.
We also check to see if the structure is currently a "Preview Structure" (this refers to the green placement structure) -- and we only want to continue if it's the real thing, and not a preview.
Most of this logic will be run server-side, hence the "Switch Has Authority".
One of the first things we do is call a custom function called "Check Panel Status". This function will check all of the details needed to determine if the solar panel should be on or not, and then sets the container active/inactive based the results, and this "Check Panel Status" function will be called multiple times, in multiple places.
As you can see, most of this logic is contained in the "Get Solar Panel Status" function. We'll look into that in more detail later, but for now, let's stick with the "Event Being Play" logic.
The next thing we'll do is call the "Day Cycle Manger". This handles the in-game time system, and contains useful information about whether or not it's currently daylight outside, etc.
One of the most important features of the Day Cycle Manger, is the ability to "bind delegates" to certain events. In this case, we're able to bind custom events to the "On Start Daytime" and "On Start Nighttime" events. This means that whenever Day Cycle Manager determines that it's daytime or nighttime has happened, it will trigger our custom events.
We also have a check to see if it's currently nighttime. Why? Because if it's nighttime, we need to check to see if the batteries are still charged enough to keep the solar panel online, and if not, to disable the solar panel. To do that, we setup a looped timer which will call the "Check Panel Status" function every 10 seconds, which nicely equates to 5 minutes in-game.
This shows our custom events that trigger when day or night happen.
- When day starts: We clear the timer (since the batteries only run at night), and we run a "Check Panel Status" to trigger the switch to using solar power (instead of batteries), if sunlight is available.
- When day ends: We count the number of batteries currently in the panels inventory, and we multicast that value to everyone, then set the looping timer and run another "Check Panel Status"
This "MULTICAST - Set Number of Batteries" function is important, and will be used in a few different places, as we'll see soon.
Next, we need the ability to draw text at the bottom of the Solar Panel whenever a player looks at it, so that they can tell what the current status of the panel is. For example:
This shows that the panel has solar power, but there aren't any batteries available for charging.
To achieve this HUD message, go to our "SolarPanel_BP" blueprint, and right-click the "Blueprint Draw HUD" function and click "Implement Function". Then we can add the following logic:
As you can see, this function calls the main "Get Solar Panel Status" function again, which returns the desired HUD text color, as well as the HUD message.
Then, all we have to do is offset the "Y" location by 100, which will push the text downwards. "BP Draw Text Centered" will keep the text nicely centered in the screen, regardless of character length.
Okay, now for the big one!
Let's look at the main "Get Solar Panel Status" function, which calculates whether or not the panel is able to be powered, how much battery life is remaining, and what HUD text/colors should be returned.
Right off the bat, let's setup two local variables called "Is Daytime" and "Is Indoors". Both of those will be used later. We get the "Is Daytime" value directly from the Day Cycle Manger, and we can get the "Is Indoors" value from the "Is Indoors at Loc" built-in function.
Note: I added a +100 offset in the Z direction (100 units up off the ground) so that the game didn't register the structure as being inside the foundation that it's placed on.
Now for the fun part: We need to calculate the amount of battery power remaining.
In this piece, we take the usable number of batters (which was set earlier in the MULTICAST event), and we multiply by the number of seconds in an hour, and how many hours we want each battery to run for.
Note: These are in-game hours, not real-life hours.
We then add this value to the "Day Time End" (the time when night began) from the Day Cycle Manager, and subtract the current time. This gives us our countdown based on how many batteries we have in the solar panel's inventory. We take the "Max" value to guarantee that the timer will stop at zero, instead of going into negative numbers. This value is then assigned to the "Battery Time Remaining" local float variable on our main execution path.
Now for the fun part. We need to decide what message the HUD will display, based on the information we know (Is Indoors, Is Daytime, Number of Batteries, and Battery Time Remaining). What this ends up creating is a simple decision tree. I usually draw out the tree on graph paper before I start coding, which really helps me simplify the process in my head.
The tree starts on the right-hand side. If the solar panel is located indoors, then the panel overrides all previous message and issues a warning.
If the structure in not indoors, then we check to see if it's currently daytime. If it is, then we check to see if we have any batters and display the appropriate message. If it's not daytime, then we check to see if we have any battery power remaining, and display the appropriate message (including a countdown timer to display the amount of battery power remaining).
The last step of this function is to calculate whether or not the solar panel should have power, and what color the resulting HUD text should be.
As you can see, the solar panel has to have either solar power or available battery power in order for "Power Available" to be true, otherwise it's false. If the power is on, we color the text orange, otherwise it's gray.
Believe it or not, that's the end of the SolarPanel_BP graph! You did it!
Setting up the Solar Panel inventory component
Last, but not least, we'll need to make an inventory component for our solar panel. This will be where batteries are crafted and stored. Create a new blueprint called "PrimalInventoryBP_SolarPanel" and add it to your "SolarPanel_BP" blueprint, in the component's tab.
Next, add the following items to your new inventory:
This is a pretty standard inventory.
Note the following things:
- BP Notify Item Added / Removed: We need to check these boxes, so that we can use these blueprint functions later.
- Max Inventory Items: Make the panel's storage as big or small as you want. In this case, I chose 50, because that seems like enough room to comfortably store a dozen or so batteries, plus any crafting components the player might need to add.
- Remote Add Item Only Allow Item Classes: This allows us to limit the solar panel's inventory to only batteries, and the items that make the batteries. I consider this a good best practice for these types of structures, so players don't just throw random items in these types of inventories. Nobody's poop or spoiled meat should be in the solar panel. =)
- All Default Inventory is Engrams: That's an important one. It means that all blueprints in the inventory are considered to be engram blueprints, meaning that they can't be removed from the station. Note: The "Battery" primal item is labeled as an "Always Learned Engram", which allows it to show up here, and be treated like an engram, even though the player did not unlock it in their engram list.
Now, let's get back to those "BP Notify Item Added / Removed" functions we mentioned earlier.
For the "Added" function, we want to detect when a battery has been deposited, and increment the solar panel's number of available batteries -- but only if it's daytime. Batteries added at night are not considered charged yet.
Similarly, with the "Removed" function, we need to verify that the current number is less than the existing number before we change the "number of charged batteries" count on the solar panel.
For example, if the solar panel started the evening with 5 batteries, then adding 10 more and removing 1 would trigger the "Remove" function to execute, and the structure would think that it had 14 batteries -- even though we still only consider 5 of them charged. In other words, when day flips to night, we cannot gain any "new" charged batteries until the next day, since batteries only recharge in sunlight.
Finally, you'll need to create an engram entry for the panel, and update your PrimalGameData file with the "Additional Structure to Place" and the "Additional Engram Entry" and then you're done!
You've made a fully functional solar panel with battery backup!
Feel free to edit/change this project as much as you want for your own use.
This project will be uploaded as a stand-alone mod, with a link to download the open-source code. Enjoy!