#include "PatchManager.hpp" #include "client/app/AppPlatform.hpp" #include "common/Utils.hpp" #include "world/tile/Tile.hpp" #include "world/item/Item.hpp" #include "thirdparty/GL/GL.hpp" #define PM_SEPARATOR ('|') PatchManager* g_pPatchManager; PatchManager* GetPatchManager() { if (!g_pPatchManager) g_pPatchManager = new PatchManager; return g_pPatchManager; } PatchManager::PatchManager() { m_bGrassTinted = true; m_bGlassSemiTransparent = false; m_nMetalSideYOffset = -1; } void PatchManager::LoadPatchData(const std::string& patchData) { std::stringstream patchDataStream(patchData); std::string currLine; while (std::getline(patchDataStream, currLine)) { if (currLine.empty()) continue; if (currLine[0] == '#') continue; std::string command; std::stringstream lineStream(currLine); // read command type if (!std::getline(lineStream, command, PM_SEPARATOR)) continue; if (command == "stop_now") { LOG_I("PatchManager: Found stop_now, quitting patch processing earlier, iProgramInCpp probably wanted to test something"); return; } if (command == "terrain" || command == "items") { bool bIsItems = command == "items"; std::string xStr, yStr, fileName; if (!std::getline(lineStream, xStr, PM_SEPARATOR)) continue; if (!std::getline(lineStream, yStr, PM_SEPARATOR)) continue; if (!std::getline(lineStream, fileName, PM_SEPARATOR)) continue; // turn the xStr and yStr into ints. int x, y; if (!sscanf(xStr.c_str(), "%d", &x)) continue; if (!sscanf(yStr.c_str(), "%d", &y)) continue; m_patchData.push_back(PatchData(bIsItems ? TYPE_ITEMS : TYPE_TERRAIN, x, y, fileName)); continue; } if (command == "frame") { std::string xStr, yStr, itemName; if (!std::getline(lineStream, itemName, PM_SEPARATOR)) continue; if (!std::getline(lineStream, xStr, PM_SEPARATOR)) continue; if (!std::getline(lineStream, yStr, PM_SEPARATOR)) continue; int itemID = -1, x = 0, y = 0; if (!sscanf(xStr.c_str(), "%d", &x)) continue; if (!sscanf(yStr.c_str(), "%d", &y)) continue; // try to parse the item name as an int first if (sscanf(itemName.c_str(), "%d", &itemID)) { if (itemID < 0 || itemID >= C_MAX_ITEMS) goto namefailure; if (itemID < C_MAX_TILES && !Tile::tiles[itemID]) goto namefailure; if (itemID >= C_MAX_TILES && !Item::items[itemID]) goto namefailure; } else { std::string tileDesc = "tile." + itemName; std::string itemDesc = "item." + itemName; // look through the entirety of the Tiles and Items array for (int i = 0; i < C_MAX_TILES && itemID == -1; i++) { if (!Tile::tiles[i]) continue; if (Tile::tiles[i]->m_descriptionID != tileDesc) continue; itemID = i; } for (int i = 0; i < C_MAX_ITEMS && itemID == -1; i++) { if (!Item::items[i]) continue; if (Item::items[i]->m_DescriptionID != itemDesc) continue; itemID = i; } } if (itemID == -1) { namefailure: LOG_W("Unknown item/tile with the name %s", itemName.c_str()); continue; } m_patchData.push_back(PatchData(TYPE_FRAME, itemID, 16 * y + x)); continue; } // features -- TODO un-hardcode this if (command == "vegetation_tint") { ReadBool(lineStream, m_bGrassTinted); continue; } if (command == "semi_transparent_glass") { ReadBool(lineStream, m_bGlassSemiTransparent); continue; } if (command == "metal_block_sides") { ReadInt(lineStream, m_nMetalSideYOffset); continue; } if (command == "grass_sides_tint") { ReadBool(lineStream, m_bGrassSidesTinted); continue; } LOG_W("Unknown command %s from patch data.", command.c_str()); } } void PatchManager::PatchTextures(AppPlatform* pAppPlatform, ePatchType patchType) { // Use glTexSubImage2D to patch the terrain.png texture on the fly. for (int i = 0; i < int(m_patchData.size()); i++) { PatchData& pd = m_patchData[i]; if (pd.m_type != patchType) continue; Texture texture = pAppPlatform->loadTexture("patches/" + pd.m_filename, true); if (texture.m_width == 0) { LOG_W("Image %s has width 0, not found?! Skipping", pd.m_filename.c_str()); continue; } glTexSubImage2D( GL_TEXTURE_2D, 0, pd.m_destX, pd.m_destY, texture.m_width, texture.m_height, GL_RGBA, GL_UNSIGNED_BYTE, texture.m_pixels ); SAFE_DELETE_ARRAY(texture.m_pixels); } } void PatchManager::PatchTiles() { for (int i = 0; i < int(m_patchData.size()); i++) { PatchData& pd = m_patchData[i]; if (pd.m_type != TYPE_FRAME) continue; if (pd.m_destID < C_MAX_TILES && Tile::tiles[pd.m_destID]) { Tile::tiles[pd.m_destID]->m_TextureFrame = pd.m_frameNo; continue; } if (Item::items[pd.m_destID]) { Item::items[pd.m_destID]->m_icon = pd.m_frameNo; continue; } LOG_W("PatchTiles: unknown item ID %d", pd.m_destID); } } bool PatchManager::IsGrassTinted() { return m_bGrassTinted; } int PatchManager::GetMetalSideYOffset() { return m_nMetalSideYOffset; } bool PatchManager::IsGlassSemiTransparent() { return m_bGlassSemiTransparent; } bool PatchManager::IsGrassSidesTinted() { return m_bGrassSidesTinted; } void PatchManager::ReadBool(std::istream& is, bool& b) { std::string flag; if (!std::getline(is, flag, PM_SEPARATOR)) return; b = (flag == "true" || flag == "1" || flag == "TRUE"); } void PatchManager::ReadInt(std::istream& is, int& i) { std::string flag; if (!std::getline(is, flag, PM_SEPARATOR)) return; int x = -1; if (sscanf(flag.c_str(), "%d", &x)) i = x; }