Download

SQLite 3 Implementation Into Unreal Engine 4

Some have requested help for this so I hope this helps some. Note this was adapted to a similar free wrapper made for Torque Game Engine just rewrote a few lines for the Unreal Adaptation.

First Download the SQLite C++ files here: MEGA

PasteBin Usage:

Next Extract the Classes and RPG_Database.h and .cpp Folder into your project’s source folder: Source[Gamename]\

Include the Class Folder Directory to your C++ Project.

Include the RPGDatabase files to the main code.

The RPG Database object is the BP instancing object. Because it uses a local database I placed all my interaction for the database in the Gamestate Object. All interactions with the actual database happens in sequence and through the one object. I am unsure if SQLite supports multi threaded interactions. So far what I needed for works without issues.

//Note - The database file I originally saved in the save directory but I recently moved them to the game content folder. I hope that this makes the engine package the files during the baking process when making a deployment package. I have not tested this but hopefully this will work. I will also have to make it where the current database will be copied to the save directory to simulate the real world usage for database/save file data.

//Initializing the Database file. - This is just what I use to copy a fresh database file from the source and make it my currently active one. This is so that updates can be made to the source and all activities saved to the current will only be in a copied database. Also are a few functions that I use to help keep the SQL statements clean.




URPG_Party::URPG_Party(const class FPostConstructInitializeProperties& PCIP)
    : Super(PCIP)
{

    ItemInv = PCIP.CreateDefaultSubobject<URPG_Inventory>(this, TEXT("ItemInv"));
    ArmorInv = PCIP.CreateDefaultSubobject<URPG_Armor>(this, TEXT("ArmorInv"));
    PartyMem = PCIP.CreateDefaultSubobject<URPG_PartyMembers>(this, TEXT("PartyMem"));

    CurrentFieldPlayer = 0;
    Money = 5000;
    CurrentFieldPlayerHandel = 0;
    PartyLeaderIndex = 0;
    TimePlayed = 0;
    CurrentMap = "";

    DB_SOURCE_PATH = FPaths::GameContentDir()+"RPG_SYSTEM/datafiles/datastore/";
    DB_ACTIVE_PATH = FPaths::GameContentDir() + "RPG_SYSTEM/datafiles/";
    DB_SAVE_PATH = FPaths::GameContentDir() + "RPG_SYSTEM/datafiles/datasect/";
    DB_SOURCE = "source.dat";
    DB_ACTIVE = "active.dat";
    DB_SAVESLOT1 = "save1.dat";
    DB_SAVESLOT2 = "save2.dat";
    DB_SAVESLOT3 = "save3.dat";
    SourceDataBase = DB_SOURCE_PATH + DB_SOURCE;
    CurrentDataBase = DB_ACTIVE_PATH + DB_ACTIVE;
}


bool URPG_Party::initalizeDataBaseFile(){
    //Check File 
    if (FPlatformFileManager::Get().GetPlatformFile().FileExists(*CurrentDataBase))
    {
        echo("ActiveDB Found will use the active one");
        return true;
    }

    if (!FPlatformFileManager::Get().GetPlatformFile().FileExists(*SourceDataBase))
    {
        error("SourceDB NOT Found Opening the database will create a blank database!");
        return false;
    }

    if (!FPlatformFileManager::Get().GetPlatformFile().CopyFile(*CurrentDataBase, *SourceDataBase))
    {
        error("Could NOT copy Source Database");
        return false;
    }
    return true;
}

void URPG_Party::initalizeDataBasePtr(URPG_Database* RPG_DATABASE){
    RPG_DATABASE_CONTROLLER = RPG_DATABASE;
}

bool URPG_Party::CHECK_DATABASE_PTR(){
    if (RPG_DATABASE_CONTROLLER == nullptr){
        echo("RPG_DATABASE_CONTROLLER Not initalized");
        return false;
    }
    return true;
}

bool URPG_Party::OpenDatabase(FString _DataBase){
    if (!CHECK_DATABASE_PTR())return false;
    if (RPG_DATABASE_CONTROLLER->OpenDatabase(TCHAR_TO_ANSI(*_DataBase)) == 0)
    {
        echo(FString("ERROR: Failed to open database: ") + _DataBase);
        echo(("       Ensure that the disk is not full or write protected.  sqliteTest aborted."));
        return false;
    }
    return true;
}


// RPG_SYSTEM
bool URPG_Party::StartUpGameData(FString CurrentMapName,bool IsNewGame){
    if (!CHECK_DATABASE_PTR())return false;
    //LevelType = GAME_LEVEL;

    //Init New Database Files

    if (IsNewGame){
        if (FPlatformFileManager::Get().GetPlatformFile().FileExists(*CurrentDataBase))
        {
            if (!FPlatformFileManager::Get().GetPlatformFile().DeleteFile(*CurrentDataBase))
            {
                error("Could Not Delete Active Database");
                return false;
            }
        }
    }
        //Sleep needed for the deletion process. 
    Sleep(1000);
    if(!initalizeDataBaseFile())return false;
        //Sleep needed for deletion and/or copy process
    Sleep(1000);

    //Create System Structures
    initalizePlayerSystem();
    InitalizeInventory();
    populateArmorData();

    //Initalize starting variables
    TimePlayed = 0;
    Money = 5000;
    CurrentMap = CurrentMapName;

    return true;
}



The code above shows some function called used to start my system. Take from it what you need.

//Reading Data VIA SQL





void URPG_Party::loadArmorPlayerType(int PlayerID, int type){

    if (!OpenDatabase(CurrentDataBase))return;
    FString SQLQuery = FString("select Armors.ArmorID,Name,ATK,DEF,MATK,MDEF,VIT,MAG,EVA,ACC,ICON,MESHSKIN,DESC,FIRE_RES,WATER_RES,EARTH_RES,WIND_RES,ICE_RES,LIGHTENING_RES,LIGHT_RES,DARK_RES,METAL_RES,CLASSES from armors join EquippedArmors on armors.ArmorID=EquippedArmors.ArmorID where playerid=")
        + FString::FromInt(PlayerID)
        +" and EquippedArmors.ArmorTypeID="
        + FString::FromInt(type)
        + ";";

    int32 result = RPG_DATABASE_CONTROLLER->BP_Query(SQLQuery);

    if (result == 0 || RPG_DATABASE_CONTROLLER->EndOfResult(result))
    {
        echo("Failed to find initial Armor");
        if (result)RPG_DATABASE_CONTROLLER->BP_ClearResult(result);
        RPG_DATABASE_CONTROLLER->BP_CloseDatabase();
        return;
    }
    else{

        int32    ID =                FCString::Atoi(*RPG_DATABASE_CONTROLLER->BP_GetColumn(result, "Armors.ArmorID"));
        FString    Name =                                RPG_DATABASE_CONTROLLER->BP_GetColumn(result, "Name");
        int32    ATK =                FCString::Atoi(*RPG_DATABASE_CONTROLLER->BP_GetColumn(result, "ATK"));
        int32    DEF =                FCString::Atoi(*RPG_DATABASE_CONTROLLER->BP_GetColumn(result, "DEF"));
        int32    MATK =                FCString::Atoi(*RPG_DATABASE_CONTROLLER->BP_GetColumn(result, "MATK"));
        int32    MDEF =                FCString::Atoi(*RPG_DATABASE_CONTROLLER->BP_GetColumn(result, "MDEF"));
        int32    VIT =                FCString::Atoi(*RPG_DATABASE_CONTROLLER->BP_GetColumn(result, "VIT"));
        int32    MAG =                FCString::Atoi(*RPG_DATABASE_CONTROLLER->BP_GetColumn(result, "MAG"));
        int32    EVA =                FCString::Atoi(*RPG_DATABASE_CONTROLLER->BP_GetColumn(result, "EVA"));
        int32    ACC =                FCString::Atoi(*RPG_DATABASE_CONTROLLER->BP_GetColumn(result, "ACC"));
        int32    ARMORTYPE =            FCString::Atoi(*RPG_DATABASE_CONTROLLER->BP_GetColumn(result, "ARMORTYPE"));
        FString    MESHSKIN =                            RPG_DATABASE_CONTROLLER->BP_GetColumn(result, "MESHSKIN");
        FString    DESC =                                RPG_DATABASE_CONTROLLER->BP_GetColumn(result, "DESC");
        int32    FIRE_RES =            FCString::Atoi(*RPG_DATABASE_CONTROLLER->BP_GetColumn(result, "FIRE_RES"));
        int32    WATER_RES =            FCString::Atoi(*RPG_DATABASE_CONTROLLER->BP_GetColumn(result, "WATER_RES"));
        int32    EARTH_RES =            FCString::Atoi(*RPG_DATABASE_CONTROLLER->BP_GetColumn(result, "EARTH_RES"));
        int32    WIND_RES =            FCString::Atoi(*RPG_DATABASE_CONTROLLER->BP_GetColumn(result, "WIND_RES"));
        int32    ICE_RES =            FCString::Atoi(*RPG_DATABASE_CONTROLLER->BP_GetColumn(result, "ICE_RES"));
        int32    LIGHTENING_RES =    FCString::Atoi(*RPG_DATABASE_CONTROLLER->BP_GetColumn(result, "LIGHTENING_RES"));
        int32    LIGHT_RES =            FCString::Atoi(*RPG_DATABASE_CONTROLLER->BP_GetColumn(result, "LIGHT_RES"));
        int32    DARK_RES =            FCString::Atoi(*RPG_DATABASE_CONTROLLER->BP_GetColumn(result, "DARK_RES"));
        int32    METAL_RES =            FCString::Atoi(*RPG_DATABASE_CONTROLLER->BP_GetColumn(result, "METAL_RES"));
        FString    CLASSES =                            RPG_DATABASE_CONTROLLER->BP_GetColumn(result, "CLASSES");
        
        PartyMem->equipArmorStats(PlayerID, type, Name, ATK, DEF, MATK, MDEF, VIT, MAG, EVA, ACC);
        PartyMem->equipPlayerRes(PlayerID, type, FIRE_RES, WATER_RES, EARTH_RES, WIND_RES, ICE_RES, LIGHTENING_RES, LIGHT_RES, DARK_RES, METAL_RES);
    }
    if (result)RPG_DATABASE_CONTROLLER->BP_ClearResult(result);
    RPG_DATABASE_CONTROLLER->BP_CloseDatabase();
}



Hope this helps some people…

1 Like

Thank you a lot :smiley:

Please note all that this only works in 4.4.3 and below. When I try to update to 4.5.1 i get precompile header errors. I am trying to figure out why this is happening. I have even modified the precompile header properties and still no go. Will update once i figure this out. Or if anyone has a solution please feel free to share. Thanks.

I’m still having the problems with sqlite3.c and shell.c because precompiled headers… Trying to solve the problem too…

roll back to 4.4.3. I have not gotten any answer on answers yet.

Thanks Shoiko! This is going to be very helpful when I extend my inventory system to use databases (Having to create a wrapper was holding me back, now I don’t have to!)

Not only for inventory but for any type of persistent data. Very nice!

Thank you so much ! It’s something that i will need for my project .
Some tutorials will be very usefull for saving inventory in db.

I have a solution. The reason for this is error is your complete wrong way of including third party libraries in your game’s code. Had a similar problem before and it took me some time to sort it out (https://wiki.unrealengine.com/Linking_Static_Libraries_Using_The_Build_System, Source Build Errors - UE4 AnswerHub - were the most useful links). I will try to describe process and also upload archive with files.

  1. Compile your 3d party code into a lib for x64.
  2. Create ThirdParty folder in your project folder (MyProject, etc).
  3. Create the following folder structure:
    sqlite3/include/ -> put .h files here
    sqlite3/lib/x64 -> put your compiled lib files here

Now comes the tricky part. We must inform UBT to use our ThirdParty folder as an additional source of includes and libraries.
4. Open your <project_name>.Build.cs (in my case, MyProject.Build.cs)
5. after


using UnrealBuildTool; 

add


using System.IO;

  1. add two helper functions to the existing class:

   private string ModulePath
    {
        get { return Path.GetDirectoryName(RulesCompiler.GetModuleFilename(this.GetType().Name)); }
    }
    private string ThirdPartyPath
    {
        get { return Path.GetFullPath(Path.Combine(ModulePath, "../../ThirdParty/")); }
    }

  1. In MyProject function, add the following at the end:

LoadSqlite3(Target);

  1. add additional function to a class:

public bool LoadSqlite3(TargetInfo Target)
    {
        bool isApplied = false;

        if ((Target.Platform == UnrealTargetPlatform.Win64))
        {
            isApplied = true;
            string LibraryPath = Path.Combine(ThirdPartyPath, "sqlite3", "lib");
            //string LibraryName = "sqlite3";
            if (Target.Platform == UnrealTargetPlatform.Win64)
            {
                LibraryPath = Path.Combine(LibraryPath, "x64");
            }
            PublicLibraryPaths.Add(LibraryPath);
            PublicAdditionalLibraries.Add(Path.Combine(LibraryPath, "sqlite3.lib"));
            PublicIncludePaths.Add(Path.Combine(ThirdPartyPath, "sqlite3", "include"));
        }
        return isApplied;
    }


As you can see I use only Win64 but if you need more platforms, feel free to compile 'em and add to if/else if in LoadSqlite3 function. You can see different platforms, for example, here: \Engine\Source\ThirdParty\zlib\zlib.Build.cs


#include "sqlite3.h" 

add this line to file where you want to use sqlite3.

That’s all, hope this helps. :slight_smile:

Forgot to add uploaded archive: http://uploaded.net/file/spdnoyj0. Folder structure for third party code (in our case - sqlite3) + example build file

Oh, and a friendly advice for Shoiko, try to use containers which are provided by UE and don’t mess with STL :cool:

Before I did not have to make a plugin to get this to work. Even the staff told me how to integrate the library without making it into a wrapped module since it was optional, I’ll try this soon but also note that they have a pull request to add SQLite as a plugin that may be accepted.

https://answers.unrealengine.com/questions/122492/updating-to-45-broke-precompiled-headers.html

I mainly did not try plugins as they over whelmed me at first. When I finish my RPG System I wanted to try to make it a module before finishing everything up. But I will have to try this in the upcoming weeks. Thanks.

IT WORKS!!! :D!! I tried your solution and works perfectly well :D!!! Just be watch with the route of the folder

This looks really helpful as I’m trying to build a small size dedicated server for a prototype of one of my games, and I desperately needed some sort of persistent data storage.

The only thing that stops me from implementing it right away is that people say they’ll include this solution (or a similar one) in 4.6 so I guess that it’s worth to wait for that little longer

I’m sorry this is not my source. my source is at the top of this post. you might need to find the person who wrote that github code.

what failed the steps Shockwave-peter said was dead on.

You have to make the SQLite files into a third party package and follow peters directions. As for the as for RPGSystem_Database that goes into your code to bridge the C++ to Blueprint. If you cant compile it you might have not changed the links from the path to the third party:

You can also Create your own class and build the link to SQLite witht he RPG database as a example.

Got this to work with 4.14.1 but had to change the ModulePath of the MyProject.Build.cs code…



    private string ModulePath
    {
        get { return ModuleDirectory; }
    }
    private string ThirdPartyPath
    {
        get { return Path.GetFullPath(Path.Combine(ModulePath, "../../ThirdParty/")); }
    }


Every link is down currently.
I read that UE4 has also integrated SQLite support, but I did find anything really helpful to set it up.
I want to store users, a banlist and maybe stats in it.

Moved files around:

https://mega.nz/#!wpgUmQbQ!SISs9q8acP7a3CHXqLSU5OjIRMSMn6V3wYbGRCMPPnw

PasteBin Usage:

Cool, will have a look at it when I am home; thx!
It is possible to insert with this one right?
(I also found this implementation, which only can read data and seems to be discontinued GitHub - KhArtNJava/SQLite3UE4: SQLite3 Database Plugin for Unreal Engine 4)

We hope this plugin can help you.

HiSQLite3 (SQLite3 For UE4)