diff --git a/src/gamedata/CMakeLists.txt b/src/gamedata/CMakeLists.txt index f5c3668..2a4649d 100644 --- a/src/gamedata/CMakeLists.txt +++ b/src/gamedata/CMakeLists.txt @@ -2,11 +2,17 @@ project(gamedata) set(CMAKE_CXX_STANDARD 17) find_package(OGRE REQUIRED COMPONENTS Bites Bullet Paging Terrain Overlay CONFIG) find_package(Bullet REQUIRED) +find_package(nlohmann_json REQUIRED) add_library(GameData STATIC GameData.cpp CharacterModule.cpp WaterModule.cpp SunModule.cpp TerrainModule.cpp GUIModule.cpp LuaData.cpp WorldMapModule.cpp BoatModule.cpp EventTriggerModule.cpp CharacterAnimationModule.cpp PhysicsModule.cpp EventModule.cpp CharacterManagerModule.cpp VehicleManagerModule.cpp AppModule.cpp SmartObject.cpp SlotsModule.cpp goap.cpp) -target_link_libraries(GameData PUBLIC lua flecs::flecs_static OgreMain OgreBites +target_link_libraries(GameData PUBLIC + lua + flecs::flecs_static + nlohmann_json::nlohmann_json + OgreMain + OgreBites OgrePaging OgreTerrain OgreOverlay PRIVATE sceneloader world-build physics editor) target_include_directories(GameData PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${BULLET_INCLUDE_DIR} ../luaaa) diff --git a/src/gamedata/GUIModule.cpp b/src/gamedata/GUIModule.cpp index 3180433..bfd65d0 100644 --- a/src/gamedata/GUIModule.cpp +++ b/src/gamedata/GUIModule.cpp @@ -700,6 +700,7 @@ struct EditorGUIListener : public Ogre::RenderTargetListener { bool locationSelected = false; float strength = 0.0f; int size = 0; + long slot_x, slot_y; void updateWorldTexture() { // Get the hardware pixel buffer @@ -748,16 +749,33 @@ struct EditorGUIListener : public Ogre::RenderTargetListener { ECS::get().mTerrainGroup->update(true); } - void setCameraPos() + void setCursorPos(Ogre::Vector3 &cursorPosition, + Ogre::Quaternion &orientation) { Ogre::Vector3 worldPos = - ECS::get().mCameraPivot->_getDerivedPosition(); + ECS::get().sceneNode->_getDerivedPosition(); worldPos.x = TerrainModule::get_world_x(selected_x); worldPos.z = TerrainModule::get_world_y(selected_y); + worldPos.y = TerrainModule::get_height( + ECS::get().mTerrainGroup, worldPos); + ECS::get().sceneNode->_setDerivedPosition( + worldPos); + cursorPosition = worldPos; + orientation = ECS::get() + .sceneNode->_getDerivedOrientation(); + } + void setCameraPos() + { + Ogre::Vector3 cursorPos; + Ogre::Quaternion cursorOrientation; + setCursorPos(cursorPos, cursorOrientation); Ogre::Vector3 cameraPos = ECS::get().mCameraPivot->_getDerivedPosition(); - cameraPos.x = worldPos.x; - cameraPos.z = worldPos.z; + Ogre::Vector3 cameraOffset = + cursorOrientation * Ogre::Vector3::UNIT_Z * 30.0f; + cameraPos.x = cursorPos.x; + cameraPos.z = cursorPos.z; + cameraPos += cameraOffset; cameraPos.y = TerrainModule::get_height( ECS::get().mTerrainGroup, cameraPos) + @@ -765,9 +783,14 @@ struct EditorGUIListener : public Ogre::RenderTargetListener { if (cameraPos.y < 0.0f) cameraPos.y = 10.0f; ECS::get().mCameraPivot->_setDerivedPosition(cameraPos); + ECS::get().mCameraPivot->_setDerivedOrientation( + cursorOrientation); cameraPos = ECS::get().mCameraGoal->_getDerivedPosition(); ECS::get().mCameraNode->_setDerivedPosition(cameraPos); + ECS::get().mCameraNode->_setDerivedOrientation( + ECS::get() + .mCameraGoal->_getDerivedOrientation()); updateHeightmap(); } void worldMapView() @@ -784,10 +807,10 @@ struct EditorGUIListener : public Ogre::RenderTargetListener { OgreAssert(TerrainModule::get_world_y(worldMap->getHeight() / 2) == 0.0f, "get_world_y"); - if (ECS::get().mCameraPivot) { + if (ECS::get().sceneNode) { Ogre::Vector3 worldPos = - ECS::get() - .mCameraPivot->_getDerivedPosition(); + ECS::get() + .sceneNode->_getDerivedPosition(); selected_x = TerrainModule::get_img_x(worldPos.x); selected_y = TerrainModule::get_img_y(worldPos.z); locationSelected = true; @@ -797,6 +820,10 @@ struct EditorGUIListener : public Ogre::RenderTargetListener { OgreAssert(selected_y >= 0 && selected_y < worldMap->getHeight(), "mix height"); + ECS::get() + .mTerrainGroup + ->convertWorldPositionToTerrainSlot( + worldPos, &slot_x, &slot_y); } ImGui::SetNextWindowSizeConstraints(ImVec2(512 + 20, 512 + 20), ImVec2(768, 768)); @@ -856,6 +883,18 @@ struct EditorGUIListener : public Ogre::RenderTargetListener { ImDrawList *draw_list = ImGui::GetWindowDrawList(); draw_list->AddCircleFilled(ImVec2(top_x + pos_x, top_y + pos_y), 1.0f, IM_COL32(0, 255, 0, 255)); + { + std::list positions; + TerrainModule::getItemPositions(&positions); + for (auto pos : positions) { + int item_x = TerrainModule::get_img_x(pos.x); + int item_y = TerrainModule::get_img_y(pos.z); + draw_list->AddCircleFilled( + ImVec2(top_x + item_x, top_y + item_y), + 3.0f, IM_COL32(255, 255, 0, 255)); + std::cout << pos << std::endl; + } + } if (locationSelected) draw_list->AddCircleFilled( ImVec2(top_x + selected_x, top_y + selected_y), @@ -877,6 +916,13 @@ struct EditorGUIListener : public Ogre::RenderTargetListener { ImGui::Text( "Selected height: %f", worldMapImage.getColourAt(selected_x, selected_y, 0).r); + { + Ogre::Vector3 position = + ECS::get() + .sceneNode->_getDerivedPosition(); + ImGui::Text("Cursor position %f %f %f", position.x, + position.y, position.z); + } if (ImGui::Button("Update terrain")) { ECS::get().mTerrainGroup->update(true); } @@ -948,6 +994,17 @@ struct EditorGUIListener : public Ogre::RenderTargetListener { setLevel = true; setLevelValue = 0.646f; } + if (ImGui::Button("Harbour")) { + Ogre::Vector3 itemPosition = + ECS::get() + .sceneNode->_getDerivedPosition(); + Ogre::Quaternion itemOrientation = + ECS::get() + .sceneNode->_getDerivedOrientation(); + TerrainModule::createItem(itemPosition, itemOrientation, + "harbour"); + TerrainModule::saveItems(); + } if (riseLower) { int actualSize = 1 + size * 2; int i, j; diff --git a/src/gamedata/TerrainModule.cpp b/src/gamedata/TerrainModule.cpp index 7a635dc..58c6a4d 100644 --- a/src/gamedata/TerrainModule.cpp +++ b/src/gamedata/TerrainModule.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "GameData.h" #include "Components.h" @@ -465,6 +466,15 @@ struct TerrainPrivate { Ogre::Timer mSunUpdate; }; +struct TerrainSlotParent { + std::pair slot; +}; +struct TerrainItem { + Ogre::Vector3 position; + Ogre::Quaternion orientation; + Ogre::String properties; +}; + TerrainModule::TerrainModule(flecs::world &ecs) { struct CanSetPlayerPosition {}; @@ -472,6 +482,8 @@ TerrainModule::TerrainModule(flecs::world &ecs) ecs.component().add(flecs::Singleton); ecs.component().add(flecs::Singleton); ecs.component().add(flecs::Singleton); + ecs.component(); + ecs.component(); ecs.component(); ecs.component().add(flecs::Singleton); ecs.import (); @@ -726,6 +738,12 @@ TerrainModule::TerrainModule(flecs::world &ecs) player.modified(); ECS::get().remove(); }); + ecs.observer("LoadTerrainItems") + .event(flecs::OnSet) + .each([](const Terrain &terrain) { + if (terrain.mTerrainGroup) + loadItems(); + }); } float TerrainModule::get_height(Ogre::TerrainGroup *group, const Ogre::Vector3 &position) @@ -765,4 +783,167 @@ void TerrainModule::save_heightmap() { HeightData::get_singleton()->save_heightmap(); } +flecs::entity TerrainModule::createItem(const Ogre::Vector3 &position, + const Ogre::Quaternion &orientation, + const Ogre::String &type) +{ + long x, y; + ECS::get().mTerrainGroup->convertWorldPositionToTerrainSlot( + position, &x, &y); + std::pair pos{ x, y }; + flecs::entity slot = + ECS::get().query_builder().build().find( + [&](const TerrainSlotParent &slot) -> bool { + return slot.slot == pos; + }); + if (!slot.is_valid()) + slot = ECS::get().entity().add(); + flecs::entity item = ECS::get().entity().child_of(slot); + nlohmann::json jproperties; + jproperties["type"] = type; + item.set({ position, orientation, jproperties.dump() }); + return item; +} +void TerrainModule::setItemProperties(flecs::entity id, Ogre::String properties) +{ + OgreAssert(id.is_valid(), "bad id"); + id.get_mut().properties = properties; + id.modified(); +} +const Ogre::String &TerrainModule::getItemProperties(flecs::entity id) +{ + OgreAssert(id.is_valid(), "bad id"); + return id.get().properties; +} +static void to_json(nlohmann::json &j, const Ogre::Vector3 &position) +{ + j["x"] = position.x; + j["y"] = position.y; + j["z"] = position.z; +} +static void to_json(nlohmann::json &j, const Ogre::Quaternion &orientation) +{ + j["w"] = orientation.w; + j["x"] = orientation.x; + j["y"] = orientation.y; + j["z"] = orientation.z; +} +static void from_json(const nlohmann::json &j, Ogre::Vector3 &position) +{ + position.x = j["x"].get(); + position.y = j["y"].get(); + position.z = j["z"].get(); +} +static void from_json(const nlohmann::json &j, Ogre::Quaternion &orientation) +{ + orientation.w = j["w"].get(); + orientation.x = j["x"].get(); + orientation.y = j["y"].get(); + orientation.z = j["z"].get(); +} +void TerrainModule::saveItems() +{ + Ogre::String path = "resources/buildings/items.list"; + if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup( + "items.list")) { + Ogre::String group = + Ogre::ResourceGroupManager::getSingleton() + .findGroupContainingResource("items.list"); + Ogre::FileInfoListPtr fileInfoList( + Ogre::ResourceGroupManager::getSingleton() + .findResourceFileInfo(group, "items.list")); + OgreAssert(fileInfoList->size() == 1, + "worpd_map.png should be there and only once"); + path = fileInfoList->at(0).archive->getName() + "/" + + "items.list"; + Ogre::FileSystemLayer::removeFile(path); + } + std::fstream fout(path.c_str(), std::ios::out); + nlohmann::json jitemlist; + ECS::get().query_builder().build().each( + [&](flecs::entity e, const TerrainItem &item) { + nlohmann::json jitem; + to_json(jitem["position"], item.position); + to_json(jitem["orientation"], item.orientation); + to_json(jitem["properties"], item.properties); + jitemlist.push_back(jitem); + }); + fout << jitemlist.dump(); + fout.close(); +} +void TerrainModule::loadItems() +{ + if (!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup( + "items.list")) + return; + Ogre::String group = Ogre::ResourceGroupManager::getSingleton() + .findGroupContainingResource("items.list"); + Ogre::DataStreamPtr stream = + Ogre::ResourceGroupManager::getSingleton().openResource( + "items.list", group); + Ogre::String json = stream->getAsString(); + nlohmann::json jlist = nlohmann::json::parse(json); + ECS::get().delete_with(); + ECS::get().delete_with(); + + for (const auto &v : jlist) { + Ogre::Vector3 position; + Ogre::Quaternion orientation; + Ogre::String properties; + from_json(v["position"], position); + from_json(v["orientation"], orientation); + properties = v["properties"].get(); + long x, y; + ECS::get() + .mTerrainGroup->convertWorldPositionToTerrainSlot( + position, &x, &y); + std::pair pos{ x, y }; + flecs::entity slot = + ECS::get() + .query_builder() + .build() + .find([&](const TerrainSlotParent &slot) + -> bool { + return slot.slot == pos; + }); + if (!slot.is_valid()) + slot = ECS::get().entity().add(); + flecs::entity item = ECS::get().entity().child_of(slot); + item.set({ position, orientation, properties }); + std::cout << "position: " << item.id() << " " << position + << std::endl; + } +} +void TerrainModule::getItemPositionPerSlot(long x, long y, + std::list *positions) +{ + std::pair pos{ x, y }; + if (!positions) + return; + flecs::entity slot = + ECS::get().query_builder().build().find( + [&](const TerrainSlotParent &slot) -> bool { + return slot.slot == pos; + }); + if (!slot.is_valid()) + return; + ECS::get() + .query_builder() + .with(flecs::ChildOf, slot) + .build() + .each([&](flecs::entity e, const TerrainItem &item) { + positions->push_back(item.position); + std::cout << e.id() << " " << item.position + << std::endl; + }); +} +void TerrainModule::getItemPositions(std::list *positions) +{ + ECS::get().query_builder().build().each( + [&](flecs::entity e, const TerrainItem &item) { + positions->push_back(item.position); + std::cout << e.id() << " " << item.position + << std::endl; + }); +} } \ No newline at end of file diff --git a/src/gamedata/TerrainModule.h b/src/gamedata/TerrainModule.h index 355050b..342ab5a 100644 --- a/src/gamedata/TerrainModule.h +++ b/src/gamedata/TerrainModule.h @@ -41,6 +41,17 @@ struct TerrainModule { static int get_img_y(float world_z); static void update_heightmap(const Ogre::Image &heightmap); static void save_heightmap(); + static flecs::entity createItem(const Ogre::Vector3 &position, + const Ogre::Quaternion &orientation, + const Ogre::String &type); + static void setItemProperties(flecs::entity id, + Ogre::String properties); + static const Ogre::String &getItemProperties(flecs::entity id); + static void saveItems(); + static void loadItems(); + static void getItemPositionPerSlot(long x, long y, + std::list *positions); + static void getItemPositions(std::list *positions); }; struct TerrainReady {}; }