Developer Diary Week 9 - Text File Input, Bug Fixing, NPC Organization
- gtristanitristani
- Jul 20, 2023
- 7 min read
I finished another week of work in contributing to this project, so am here to post another update! I was excited to begin this week particularly since it gave me the chance to slow down a bit and look back at the architecture I have built. Without the need to rush at implementing entirely new features in the project, I made a lot of progress in making it simpler to use and understand from a user perspective. I haven’t worked on creating tools this large in the past, so I wanted to make sure I had ample time to revise it as needed. After all, the end goal of this project for me is a system that is employable, understandable, and easy to extend by any user. This week, I did manage to see quite a bit done!
To start, I took some time to think about how to go about NPC creation logically. Through my research, there doesn’t seem to be a method of creating a new Actor class within a running application, or at least not directly. However, there are mechanisms to read and write to txt files in UE5 C++. Knowing this, I decided to work first on implementing the dialogue-file to dialogue-bank entry system, then see if it was viable to convert an NPC themselves to a pure text file.
After some time, I was able to implement it fully! It allows another form of input for users (like myself) that dread logging line after line of dialog through the Unreal property editor. In addition to this, the dialog file itself can be loaded from any location the user specifies.

The grammar used for it is simple and easy to understand, as shown above. At the top, there needs to be the name of the dialogue sub-bank being populated. Immediately beneath it, there is one line of dialogue per line in the file. To switch between sub-banks, there just needs to be a new line specifying its name, followed by all the lines that should fill it.

Finally, I am happy that this file input system gets rid of the current personality-based-inheritance need present in the project. In the previous setup, villagers with a certain personality effectively needed to be created as a child actor to the parent villager with that base personality. This inheritance isn’t a problem for myself, but I want to give users the freedom to use this project in whatever way they see fit. Any villager can now easily have necessary dialog banks modified and changed without the need to inherit the pre-populated dialog bank from a parent.
The majority of personality distinction is through this bank, so the idea of converting NPCs to text files began to look a bit more viable. Overall, for an NPC, there are four main blocks that would need to be converted:
Career
Gifts
Personality
Hobbies
Looking at them separated, I realized each of these blocks are effectively made up of a few different connected variables. If I could break the variables themselves into text files, the only thing needed to populate full NPCs would be these four text files, as well as their name! So I started to get to work with a simple grammar and parsing mechanism for each block.

I decided on the syntax above for Career. There are only a few necessary variables besides the career-specific dialog-bank, which could be read from a separate file for reuse across several careers with the same title. The JobTitle, Days, StartTime, EndTime, CommuteTime, WakeTime, and SleepTime variables are the only ones that remain. These are string, enum, and timestamp variables respectively.

The JobTitle string of course can be read directly into the variable. The Enum values can invoke the UEnum::GetDisplayValueAsText method for comparison to add each enum value to the days array. For the timestamp values, I decided that the grammar could be defined as an integer specifying the hour, followed by a space, and then an integer specifying the minutes. Any base career, after parsing this file, can be populated with all the information it needs when execution begins.
After working on jobs, all other building blocks primarily make use of these same base types: numeric, string, timestamp, and enum values. As a result, the rest could use a similar value parsing system, with different variables being set based on the variable’s name as specified.
Personality
Float (energy, affinity, happiness, anger, fear, sadness, excitement, PositiveMoodPercent, NegativeMoodPercent, HurtAffinity, LikedGiftAffinity, BaseGiftAffinity, DislikedGiftAffinity, TalkAffinity, HobbyAffinity, MoodGain, MoodDrain, RelaxEnergyGain, UnconsciousEnergyGain, SleepEnergyGain, JobEnergyDrain, BaseEnergyDrain, HobbyEnergyDrain, NegativeMoodEnergyDrain, MeanderPercent, HobbyPercent, ConversePercent, AffinityLevelMin, AffinityLevelMax, EnergyLevelMin, EnergyLevelMax, MoodLevelMin, MoodLevelMax)
Int (playerHits, ConverseMinExecutions, ConverseMaxExecutions)
Enum (positive preference, negative preference)
TimeStamp (MeanderMinTime, MeanderMaxTime, ConverseMinTime, ConverseMaxTime, HobbyMinTime, HobbyMaxTime)
Hobby
Timestamp (MinHobbyTime, MaxHobbyTime, HobbyDelay)
String (Name)
Gifts
String (LikedGifts, DislikedGifts)
Personality, again, has much of its data specified through the dialog bank. But because of the amount of customization, there are many more variables that can be defaulted or explicitly specified by the user. Because of this, the file can get much more lengthy depending on the level of specificity needed. Regardless, the grammar should act similarly. Hobbies only make use of variables specifying timestamps and strings. Finally, gifts can be specified solely using string variables. As a result, the rest of the blocks should take much less time to define parsing for!

This week, I moved all of the job data, job dialog, and personality dialog into this text file format for each of the villagers in the demonstration scene. While it took some time, I like the stability that the system provides and how versatile it is compared to the previous method that relied on adjusting component values manually. It’s reassuring to know that this data is all backed up in a text file that can be easily applied and accessed by any villager that needs it. At the same time, component values can be adjusted and included in finished dialog banks in addition to the dialog file input as well! A particular use for this might be adding a few unique lines for each villager without needing to define unique full dialog files for each: all character-specific dialog can be specified inside of the property settings panel if preferred.
Due to time constraints in fully figuring out UE5 text file parsing and setting up previous villagers and jobs with this functionality, I did not have the time to fully implement these three remaining blocks this week. However, I did manage to fully implement dialog files and their associated parsing for each of the current villager personalities and jobs, as well as full job parameter file parsing.
I got more done in terms of bug fixing as well! A major fault of the original code was that villagers could not generate responses in general if they didn’t have a career, which I noticed while testing the dialogue input system. After revising some of the dialog bank system, I was able to fix this problem, so villagers can use their entire available dialog bank regardless of whether or not they have a career.
Another issue I fixed involved a much earlier problem with how derived-personality villagers were set up. I initially had them inherit as child actors directly from the blueprint class BasicVillagerPersonality. The problem with this is that this class had no stat widget or dialog bank, as it was an initial first draft. At the time, I ended up creating each villager derived from this class as a unique personality, with their dialog bank and widgets added, meaning that there was a lot of unnecessary duplication. I noticed this was a large problem when cleaning up the project for use, and was able to fix it by creating a much easier to modify personality system.

Now, all villager personality types inherit from BasicVillagerPersonality_BP! This class matches a common naming convention for blueprint classes that I have been using throughout the project, and this class contains the common code used to update widgets. Now, the only modifications that need to be made to create fully-functional new personalities is public variable modification, or providing external file input to populate them.
In the end, I hope that the file parsing system will provide an easy and reusable method to fully populate each NPC at runtime without needing to do this via the property viewer within Unreal Engine. Personally, I have trouble looking at the property viewer for long periods and would prefer to enter data through external files, so I’m glad that this mechanism is now at least partially supported! I’m also happy that I made a few more quality-of-life updates that should make the system a lot easier to use. But of course, I still have a lot of work ahead of me.
For the next week, I’m going to continue my focus on bug-identification and fixing, as well as continuation of the file-parsing system. For the file-parsing system, I would like to add support to parse gifts, personality, and hobbies. After all of this is supported, I’d like to try setting up a character creator application that is able to generate these files automatically for the user. Finally, basic quality of life fixes are also ahead, as I already noticed one fault that I hope to fix next week.
Bed, career, workstations, and hobbies for each villager are all presently specified by links to actors within the scene. Setting up these links, while quick to do, is generally inconvenient. It’s something that I would like to avoid if possible, so I’d like to spend some time next week thinking on how to implement an automated setup, perhaps using each actor’s name.
Overall, I feel very on track to finish this project in the timeframe I expected! It’s something that I have had a lot of fun working on, and that taught me a lot about creating and maintaining complex AI agents over time.
I hope you enjoyed this update! Again, I’d like to encourage you to check out the project’s repository at the GitHub link below to check out the system yourself. Regardless, I hope you will look forward to next week’s update as well! Thank you for reading!
GitHub Link: https://github.com/grist-maker/NPCVillagers




