The level designers used Unreal Engine to design levels, and one of them made a plugin to export the level data. This was already done during our previous project, where the levels would be exported to JSON-files, but at the start of this project we switched to binary files to make the loading faster. I wrote a function for exporting an array of any type to a binary file, which was used in the plugin, and a function for importing a binary file to an array, which was used in our engine.
template <typename T> bool WriteBinaryFile(const std::string& aFilePath, const TArray<T>& aArray) { int count = aArray.Num(); if (count <= 0) { return false; } int bufferSize = count * sizeof(T); std::string newFilePath = aFilePath + ".jazz"; std::ofstream file(newFilePath.c_str(), std::ios::out | std::ios::binary); file.write((char*)&count, sizeof(int)); file.write((char*)&aArray[0], bufferSize); file.close(); return true; }
I also wrote the structs which were used to store the level data. The file containing the structs was located in our engine, but was also included by the plugin, so that any changes would affect both export and import at the same time.
struct StaticMeshData { Vector3f position; Quaternion rotation; Vector3f scale; int modelIndex; }; struct LightData { Vector3f position; Vector3f direction; Color color; float constantIntensity; float linearIntensity; float quadraticIntensity; //if range < 0 it's a directional light float range = -1.0f; //if range >= 0 and angle < 0 it's a point light //otherwise it's a spot light, but they were added in the next project float innerAngle = -1.0f; float outerAngle = -1.0f; bool shouldCastShadow = false; }; struct PrefabData { int prefabID; Vector3f position; Quaternion rotation; Vector3f scale; size_t metaTag = 0; size_t metaTag2 = 0; size_t metaTag3 = 0; }; //structs for static collison and node graphs were added in the next project
When the game started all level files were loaded and the data was stored in arrays. This data would then be used to create all level objects when a level was loaded. The current level would automatically reload when the files changed, but not in the completed game.
void LevelLoader::ReadAllFiles() { CU::GrowingArray<std::string> files = CU::FindFiles(myDirectory, myFileEnding); for (int index = 0; index < files.Size(); ++index) { const std::string& filePath = files[index]; std::string levelName = filePath.substr(myDirectory.size()); if (STRING_ENDS_WITH(levelName, myArtEnding)) { REMOVE_STRING_ENDING(levelName, myArtEnding); LevelData& levelData = GetLevelData(levelName); levelData.myArtFile = filePath; } //same thing for lights and prefabs } for (int index = 0; index < myLevels.Size(); ++index) { LevelData& levelData = myLevels[index]; if (!CU::ReadBinaryFile(levelData.myArtFile, levelData.myArt)) { PRINT_R("Could not find art file for %s", levelData.myName.c_str()); } //same thing for lights and prefabs } } LevelLoader::LevelData& LevelLoader::GetLevelData(const std::string& aLevelName) { int levelIndex = GetLevelIndex(aLevelName); if (levelIndex < 0) { myLevels.Add(LevelData()); LevelData& levelData = myLevels.GetLast(); levelData.myName = aLevelName; levelData.mySkyBoxAlias = mySkyboxDirectory + aLevelName + mySkyboxEnding; levelData.myArt.Init(1); levelData.myLights.Init(1); levelData.myPrefabs.Init(1); return levelData; } else { return myLevels[levelIndex]; } }