For the last few versions, patch notes and downloads have been mirrored to our GitHub Releases page. Starting from upcoming July builds, our Releases page will be the official site to find new builds of Daggerfall Unity. Live Builds will be retired and redirect to Releases.
This comes with a few advantages. Patch notes, source, and downloads for each release now all live together in one place, and a longer release history can be maintained. Whereas Live Builds would only keep last two or three builds, Releases can retain all new versions going forwards. It also means new releases can be curated by other developers as future stewardship of Daggerfall Unity broadens beyond myself.
This is part of a strategy to make GitHub the primary Daggerfall Unity site in time for 1.0 release. As a project that has now been worked on by over 50 people across 5+ years, it doesn’t make sense for a personal blog site to be the centre of such an endeavour. I’ll have more to share about this as 1.0 approaches later in 2021.
Development History
Daggerfall Workshop started as a personal blog site outlining my journey creating exploring tools for Daggerfall. Since Daggerfall Unity reached classic parity in 2019, most of the posts here have been patch notes in bullet format. But if you look back over posts from a few years ago, there were more interesting and technical updates as the energy of development was in full swing.
My sentiment is the basic patch notes are starting to bury more interesting posts from DFU’s long development history. Rather than continue this trend, I’d like Daggerfall Workshop to stand as a journal of one person’s mad obsession gradually leading into a rather astounding fan remake that has since outgrown the person who started it.
Back to Its Roots
I’ll still post major news and events here on the Workshop, and I might even use it as a personal devblog again someday. There’s a future coming for Daggerfall Unity that doesn’t need me to manage every release and review every line of code. In that future, I’m just one more person who loves this game. I might at last have some time just to play for fun and build mods of my own on the side.
And someday after 1.0, once I’ve had time to decompress and organise my thoughts, I’d love write a detailed postmortem of Daggerfall Unity’s development. This would be a fitting capstone to the Workshop after more than 20 years of tinkering on this unique game.
Information in this series is now out of date. Localizing strings in Daggerfall Unity is now possible using simple font and text files only. It is no longer necessary to use Unity Editor or write any code. A new tutorial series will be posted towards the conclusion of 0.14.x release cycle. This information is left in place for reference only.
Custom Fonts
Note: Before progressing to this tutorial, please update source project to Daggerfall Unity 0.11.3 or later. This version has fixes required to complete this part in series.
In Part 3 of this series, we noted the Korean (ko) locale would print out question mark characters (?? ???) instead of proper glyphs.
This happens because Daggerfall Unity does not yet have an appropriate font asset to render these characters. The default fonts have a full complement of Latin characters but non-Latin languages require a new font to display their unique alphabet.
This tutorial will demonstrate how to add a custom Korean font with a Hangul alphabet to Daggerfall Unity, but the same process can be used to add Cyrillic fonts, Kanji fonts, or even just a custom default font.
The font we’ll be using is Noto Serif KR from Google Fonts. Click Download family on that page to download the font used in this tutorial, or substitute with another TTF/OTF font for your language.
Once downloaded, unzip the whole font family and locate NotoSerifKR-Regular.otf. This is the specific font we’ll be using. To start with, we’ll add this font to our Unity project.
In Project view, navigate to our DemoTranslationMod/Resources folder.
Drag and drop the NotoSerifKR-Regular.otf font into this folder with other resources. Unity will import this like below.
Create TextMeshPro Font
Daggerfall Unity uses TextMeshPro (TMP) fonts. Before we can see this font in game, we need to create a TMP font asset.
Click Window menu > TextMeshPro > Font Asset Creator
Set NotoSerifKR-Regular in Source Font File by clicking the circle selector on right-hand side then selecting font
Now we need to determine which character codes our TMP font will support. This will vary based on many factors unique to the target language, but the core concept is that we want to inform Font Asset Creator which character codes from your alphabet to compile into your TMP font. Any characters not added to TMP font asset will continue to display as question marks in game.
There are multiple ways to describe which characters to use. You can select from a basic list of settings, use decimal/hex ranges, import from another TMP font, import from a file, etc. Whatever method you use, keep track of the settings so you can add to it later if any characters are found missing.
In this example, we’re going to use a subset of Hangul alphabet by directly entering the characters required. It’s better to start with a subset of characters for the region/dialect you’re targeting rather than just trying to include everything. Some languages have thousands of characters which can result in an unusable TMP atlas without enough fidelity.
In Font Asset Creator, drop down Character Set selector and choose Custom Characters
Copy and paste the following custom characters into the Custom Character List text box. Note the very first character is a space character.
The above characters are enough for this tutorial, but will need to be expanded for full language support. This is how it looks in Font Asset Creator. We’re also adding the basic English alphabet to have a well-rounded font that can still display any untranslated English text.
Click Generate Font Atlas to render all the specified characters into a TMP atlas. Once you’ve created the atlas, you’ll see all the characters packed like below. Click for full size.
TextMeshPro renders glyphs using signed distance fields (SDF). How this works is outside the scope of this tutorial, but to summarise it’s a way of representing fonts using mathematical values that can maintain smooth shapes at any resolution.
In the output field, take note of the Missing characters, Excluded characters, and “characters missing from font file”. This will display any character codes you requested but could not be found in the provided TTF/OTF font. If your source font is missing any important characters, then it’s necessary to locate another TTF/OTF font containing those characters.
Depending on your font requirements, you might want to increase Atlas Resolution, e.g. to 4096×4096 or higher to support more characters with good fidelity. You can also adjust packing method, sample size, etc. for your specific font needs.
For this tutorial, the atlas generated above is good enough. Click the Save button and save your new TMP font to DemoTranslationMod/Resources. We’ll use the default name in a moment, please don’t change it. This creates a new TMP font asset like below with the name “NotoSerifKR-Regular SDF”.
This new SDF asset contains the atlas and other information required to render the TMP font in Daggerfall Unity. You can come back and recreate the font later with different properties or more characters if needed.
Associate Font With Locale
There’s one more step before can see this font in game. We need to associate our custom font with the correct locale so that Daggerfall Unity knows to use it. This is done using the StartupScript.cs code we created previously.
Open StartupScript.cs in your code editor and replace the entire contents with below. Don’t forget to save your changes!
using UnityEngine;
using UnityEngine.Localization;
using UnityEngine.Localization.Settings;
using DaggerfallWorkshop.Game;
using DaggerfallWorkshop.Game.Utility.ModSupport;
using DaggerfallWorkshop.Game.UserInterface;
namespace DemoTranslationMod
{
public class StartupScript : MonoBehaviour
{
// Define the names of translated string table collections
const string runtimeInternalStrings = "Demo_Strings";
const string runtimeRSCStrings = "Demo_RSC";
public static Mod mod;
[Invoke(StateManager.StateTypes.Start, 0)]
public static void Init(InitParams initParams)
{
mod = initParams.Mod;
var go = new GameObject(mod.Title);
go.AddComponent<StartupScript>();
}
private void Awake()
{
// Set TextManager properties to use translated string table collections
TextManager.Instance.RuntimeInternalStrings = runtimeInternalStrings;
TextManager.Instance.RuntimeRSCStrings = runtimeRSCStrings;
// Load KO font
DaggerfallFont font_ko = new DaggerfallFont(DaggerfallFont.FontName.FONT0003);
font_ko.LoadSDFFontAsset("NotoSerifKR-Regular SDF");
// Assign KO font
Locale ko = LocalizationSettings.AvailableLocales.GetLocale("ko");
if (ko)
{
TextManager.Instance.RegisterLocalizedFont(ko, DaggerfallFont.FontName.FONT0003, font_ko);
}
Debug.Log("StartScript has completed.");
}
}
}
Let’s take a look at what changed. To start with, we added some new using statements. These import some extra functionality to the script.
using UnityEngine.Localization;
using UnityEngine.Localization.Settings;
using DaggerfallWorkshop.Game.UserInterface;
Then we added the following code to associate our custom font with the KO locale to Daggerfall’s FONT003. This is the default font used in most parts of the game.
// Load KO font
DaggerfallFont font_ko = new DaggerfallFont(DaggerfallFont.FontName.FONT0003);
font_ko.LoadSDFFontAsset("NotoSerifKR-Regular SDF");
// Assign KO font
Locale ko = LocalizationSettings.AvailableLocales.GetLocale("ko");
if (ko)
{
TextManager.Instance.RegisterLocalizedFont(ko, DaggerfallFont.FontName.FONT0003, font_ko);
}
First, we create a custom DaggerfallFont called font_ko. By default we’re loading FONT003, but we’ll replace this in a moment with our custom font.
Second, we tell font_ko to load our custom font asset using LoadSDFFontAsset(). Any font created using the TextMeshPro Font Asset Creator should load OK. Reminder: you need to be on Daggerfall Unity 0.11.3 or later.
Finally, we try to get the “ko” locale and only continue if this locale is found. If the locale is found, we associate our custom DaggerfallFont with the “ko” locale using RegisterLocalizedFont().
When this code executes at startup, Daggerfall Unity now knows it should use a different font when rendering FONT003 within the Korean (ko) locale. You can associate the same SDF font with FONT001, FONT002, etc. but you might want to use different styles of typefaces to better match the desired look and feel in your translation.
Make sure your changes are saved, then we can try this font in game.
Click Play to start the game and click through to title menu.
Use the locale drop-down to select Korean (ko) in Game view.
Click Start New Game in title menu. If everything works as expected, our custom font will be selected and used with our translated text example.
Click Play again to stop game.
To summarise, creating a custom font requires the following steps:
Locate appropriate TTF/OTF source fonts for your language. These fonts must contain all the alphabet characters you need for your translation.
Import the TTF/OTF font into Unity project.
Use the Font Asset Creator to generate a custom TMP font asset with the required characters and resolution.
Associate new font with your custom locale and related Daggerfall font in startup C# script.
You might need to recreate font several times when creating your translation mod, either to add new characters, change resolution, or just finetune the look and feel. If you change the asset name, don’t forget to update this in your startup script.
Now that we have a custom font, we can move on to packaging our localisation to standalone files. This will be covered in Localizing Strings in Daggerfall Unity – Part 7.
Daggerfall Unity 0.11.3 is now available on Live Builds page. This is another general bug-fix release with some updates to mod system.
Starting from this release, I’m attaching zipped builds along with patch notes to Releases page on GitHub. This will eventually become a longer-term archive for older builds even after they’re cleaned up from Live Builds page. If there’s enough demand, I can work through attaching older builds to previous releases on this page.
Now that I’m finally caught up with code review, I’ll be able to get back into the localization tutorial series. This series was pending some fixes rolled out in 0.11.2 and 0.11.3, so please be sure to update before the next article in series is published.
Quest Debugger Input Changes
The quest debugger has a few changes to input settings. These changes are to prevent accidentally opening debugger during normal play, free up the Tab key for other uses, and to make shortcuts easier on non-US keyboards. For example, the square bracket keys [ and ] are not so easy to use on AZERTY keyboards.
If you are not a quest author or don’t care about quest debugger, you can ignore these changes.
Quest debugger is now disabled by default. Must edit EnableQuestDebugger=True in settings.ini to activate it again.
Ctrl+Shift+D now cycles through debugger display states off/partial/full
Ctrl+Shift+LeftArrow now opens previous active quest while debugger active
Ctrl+Shift+RightArrow now opens next active quest while debugger active
Ctrl+Shift+UpArrow now teleports to next dungeon quest marker while debugger active inside dungeon
Ctrl+Shift+DownArrow now teleports to previous dungeon quest marker while debugger active inside dungeon
Note: Some inputs might move character, e.g. Ctrl+Shift+D will also move character slightly to right when activating debugger. This is expected and not considered a breaking issue for a debug/development feature that is normally disabled.
General Fixes & Improvements
Pango
Potion maker: Fix issues tracking ingredient stack count between cauldron and player inventory
Conjured arrows: Don’t stack conjured arrows with different time-to-live
Daggerfall Unity 0.11.2 is now available on Live Builds page. This is a general bug-fix release with some updates to mod system.
New Features
Custom Mobile Units (TheLacus)
TheLacus has taken a big step towards support for replacing enemies with custom graphics, including 3D models. See gif below for an example of this in action using a humble cube.
If you don’t think a cube is that amazing, consider this a 3D model injected by a mod into an enemy mobile unit to alter it’s appearance. The same could be done with a fully animated 3D model. There are some limitations around this for now, notably that classic enemy attack triggers are linked to sprite animation frames. So for now a modder would also need to reimplement parts of combat to fully replace model. But this is something that can be refined over time as the community starts experimenting with this feature and sending their feedback.
Teleport To Any Dungeon Marker (Interkarma)
This is a very minor improvement to quest debugger that finally reimplements a test/cheat feature from classic. When quest debugger is open (default LeftShift+Tab) you can now use Shift+[ and Shift+] keys to cycle forwards and backwards through all markers in a dungeon. This doesn’t require a quest to be active in dungeon, only for the quest debugger to be open while player is in a dungeon. This is handy for situations like teleporting to Medora’s room in Direnni Tower, as she’s a permanent NPC without a specific quest marker.
The keybinds for quest debugger and cycling through markers can be changed in StreamingAssets/Text/DialogShortcuts.txt.
General Fixes & Improvements
Lots of bug fixes small and large from our awesome community of devs.
Hazelnut
Fix dictionary access for non-existent world variant keys
Prevent “remote” Place quest selection from randomly selecting local Place
Don’t restrict shields by plate or chain to match classic
Move hardcoded info panel colour into DaggerfallUI
Allow non-member quests to have rep requirements – to fix non-joinable Witch Coven quest dispensing
Fix Oghma removal after use to function from everywhere including wagon
AsesinoBlade
Change HotKeySequenceProcessed from Bool to Enum
Add forward thrust to click to attack – previously this move was never selected
Deepfighter
Fix formatting of date lines in diary entries of quests
KABoissonneault
Fixed misnamed formula overrides for CalculateFatigueRecoveryRate and CalculateSpellPointsRecoveryRate
Fix torch burning ticks progressing while game is paused
Fix %hpw inconsistent with classic for Dunmer characters
TheLacus
Import mod settings and presets files after create or changes from editor window
Fix mod settings not accepting negative float values
Fix mod asset loading on Turkish culture
Fix RuntimeMaterials by ignoring climate when using dungeon table
Improve support of mod localization through CSV text tables
Pango
Toggle large HUD with F10 like classic
Fix interacting with HUD when cursor not active on Linux
Fix NullReferenceException
Horse now has constant jump height to clear hedges
Jefetienne
Add joystick middle-click keybind and set joystick UI controls to protected
Prevent accidental axis button “presses” from binded movement and camera axes
XJDHDR
Reduce delay filling Dungeon variable in PlayerEnterExit
Add detailed exception handling and logging to BookReader
Automap check CombineRDB state before resetting so it stays disabled if previously set in editor
Automap move mesh and material update to separate script and optimise automap creation times
Fix texture table in dungeon automap to match environment
RuntimeMaterials automap type differentiation for interior types and other models
Add support for the discovery state of OBJ models to be saved and loaded
Fix some editor warnings
Interkarma
Fix vampires not being offered vampire quests
Restore per-task click rearming
Update DaggerfallFont to use .atlasTexture instead of deprecated .atlas
Deprioritise System Locale Selector to prevent an error during localization development
S0000011: Fix needing to click Barenziah twice with Chapter 6 before quest ends
S0000011: Fix clicking Gortwog to hand in Chapter 6 with per-task click rearming
S0000011: Reordered gold reward so it doesn’t interupt Barenziah’s information at end of quest
N0B00Y16: Fix issue of clicking on merchant at wrong time stalling quest
S0000021: Fix King of Worms potentially spawning into Sentinel during quest
S0000021: Fix logic issues with click handling carried over from classic
S0000021: Fix success condition to correctly check player has killed lich
M0B21Y19: Fix victim default home being selected as local and stashing live version of dead NPC
Information in this series is now out of date. Localizing strings in Daggerfall Unity is now possible using simple font and text files only. It is no longer necessary to use Unity Editor or write any code. A new tutorial series will be posted towards the conclusion of 0.14.x release cycle. This information is left in place for reference only.
Create Mod Settings
We’ve now created new locales, string tables, imported text, translated text, and seen how to manually enable translated text in-game. We’ve also worked through concepts unique to Daggerfall Unity like character remapping, macros, and RSC markup. The next step is to create our mod settings.
Click Daggerfall Tools menu > Mod Builder
Click Create New Mod
Navigate to path Assets/Game/Mods/DemoTranslationMod
Set Filename to DemoTranslationMod
Click Save
Fill out some information about your mod, such as mod name, version, creator name and contact, etc.
Select the platforms you want to build for. We’re just building for Windows in this tutorial.
Click Save Mod Settings to File to save our settings. This should be done any time the settings are changed in Mod Builder.
You should now have something like below (click for full size).
Click Save Mod Settings to File and close the Mod Builder window.
Verify Mod Found
After completing Part 4, you should have the DaggerfallUnityStartup scene open. If not, please open this scene now from Assets/Scenes.
Daggerfall Unity will load any mod settings found as a virtual mod when starting from launcher scene. We’re going to check our new mod settings are found.
Click editor Play button to start game
Click Mods button in launcher
Verify that Demo Translation Mod is listed under Mods Found and it is Enabled
Click editor Play button again to stop game.
Note: If you forget to stop Play from editor, your future changes will not be saved. Unity will revert editor changes when Play is stopped.
Create Mod Script
We’re now going to create a small C# script for our mod to coordinate everything at startup. To begin with, this script will simply set the translated text tables to Live String Tables, as we did manually in Part 3.
In Project view, navigate to Assets/Game/Mods/DemoTranslationMod/Assets
Right-click in empty space space inside this folder and click Create menu > Folder to create a new folder
Name this folder Scripts
Now we can create our C# script.
Navigate into Scripts folder above
Right-click in empty space inside this folder and click Create menu > C# Script to create a new C# script
Name this script StartupScript (Unity will automatically save with .cs extension)
Double-click StartupScript to open it in your configured code editor. Replace the full contents with below and save changes.
using UnityEngine;
using DaggerfallWorkshop.Game;
using DaggerfallWorkshop.Game.Utility.ModSupport;
namespace DemoTranslationMod
{
public class StartupScript : MonoBehaviour
{
// Define the names of translated string table collections
const string runtimeInternalStrings = "Demo_Strings";
const string runtimeRSCStrings = "Demo_RSC";
public static Mod mod;
[Invoke(StateManager.StateTypes.Start, 0)]
public static void Init(InitParams initParams)
{
mod = initParams.Mod;
var go = new GameObject(mod.Title);
go.AddComponent<StartupScript>();
}
private void Awake()
{
// Set TextManager properties to use translated string table collections
TextManager.Instance.RuntimeInternalStrings = runtimeInternalStrings;
TextManager.Instance.RuntimeRSCStrings = runtimeRSCStrings;
Debug.Log("StartScript has completed.");
}
}
}
Add Script To Mod
Now we have a script to set our string tables at start, we need to add this script to our mod’s list of assets.
Click Daggerfall Tools menu > Mod Builder
Select StartupScript in Project view
Click Add Selected Assets in Mod Builder
Expand Files in Mod Builder (click the little arrow next to Files to expand/contract)
Confirm that StartupScript has been added to list of assets included in mod
Click Save Mod Settings to File and close Mod Builder.
Now start the game with Play in Unity Editor. Click Play again on the launcher screen to start game as normal.
As the main game starts, you should see the following output to Console view. It will be near the end of output, but you might have to scroll up a little. The highlighted line below was emitted by our mod script, so we know it ran the Init() method.
If you don’t see the above, check that StartupScript is added to Mod Builder and you clicked Save Mod Settings to save changes. Be careful not to make editor changes while the game is playing.
Now script has executed, click on TextManager in Hierarchy view while game is running and confirm script has set correct names to Live String Tables in Inspector view. This live change by our script will only persist until game closes.
Now test translated strings are being used. We’ll test this by starting a new character as we did in Part 3.
Select French (fr) locale from selector at top-right of Game view.
Click Start New Game
Confirm French language is shown
Click Play in editor to stop the game.
We now have a Daggerfall Unity mod including translated string tables and a C# script to coordinate settings. We will continue to build on this in Localizing Strings in Daggerfall Unity – Part 6.
Get the most recent version of Daggerfall Unity:Releases