Merge branch 'noggit-shadowlands' of https://gitlab.com/prophecy-rp/noggit-red into wmo-stuff

This commit is contained in:
T1ti
2023-03-31 04:19:08 +02:00
26 changed files with 945 additions and 135 deletions

View File

@@ -56,5 +56,7 @@
<file alias="square_fs">../src/noggit/rendering/glsl/square_frag.glsl</file>
<file alias="cylinder_vs">../src/noggit/rendering/glsl/cylinder_vert.glsl</file>
<file alias="cylinder_fs">../src/noggit/rendering/glsl/cylinder_frag.glsl</file>
<file alias="line_vs">../src/noggit/rendering/glsl/line_vert.glsl</file>
<file alias="line_fs">../src/noggit/rendering/glsl/line_frag.glsl</file>
</qresource>
</RCC>

View File

@@ -22,6 +22,7 @@ void ChunkWater::from_mclq(std::vector<mclq>& layers)
{
glm::vec3 pos(xbase, 0.0f, zbase);
if (!Render.has_value()) Render.emplace();
for (mclq& liquid : layers)
{
std::uint8_t mclq_liquid_type = 0;
@@ -32,8 +33,8 @@ void ChunkWater::from_mclq(std::vector<mclq>& layers)
{
mclq_tile const& tile = liquid.tiles[z * 8 + x];
misc::bit_or(Render.fishable, x, z, tile.fishable);
misc::bit_or(Render.fatigue, x, z, tile.fatigue);
misc::bit_or(Render.value().fishable, x, z, tile.fishable);
misc::bit_or(Render.value().fatigue, x, z, tile.fatigue);
if (!tile.dont_render)
{
@@ -79,8 +80,9 @@ void ChunkWater::fromFile(BlizzardArchive::ClientFile &f, size_t basePos)
//render
if (header.ofsRenderMask)
{
f.seek(basePos + header.ofsRenderMask + sizeof(MH2O_Render));
f.read(&Render, sizeof(MH2O_Render));
Render.emplace();
f.seek(basePos + header.ofsRenderMask);
f.read(&Render.value(), sizeof(MH2O_Render));
}
for (std::size_t k = 0; k < header.nLayers; ++k)
@@ -121,9 +123,17 @@ void ChunkWater::save(sExtendableArray& adt, int base_pos, int& header_pos, int&
if (hasData(0))
{
header.nLayers = _layers.size();
if (Render.has_value())
{
header.ofsRenderMask = current_pos - base_pos;
adt.Insert(current_pos, sizeof(MH2O_Render), reinterpret_cast<char*>(&Render));
adt.Insert(current_pos, sizeof(MH2O_Render), reinterpret_cast<char*>(&Render.value()));
current_pos += sizeof(MH2O_Render);
}
else
{
header.ofsRenderMask = 0;
}
header.ofsInformation = current_pos - base_pos;
int info_pos = current_pos;

View File

@@ -7,6 +7,7 @@
#include <vector>
#include <set>
#include <optional>
class sExtendableArray;
class MapChunk;
@@ -83,7 +84,7 @@ private:
void copy_height_to_layer(liquid_layer& target, glm::vec3 const& pos, float radius);
MH2O_Render Render;
std::optional<MH2O_Render> Render;
std::vector<liquid_layer> _layers;
MapChunk* _chunk;

View File

@@ -6,7 +6,7 @@
union mcnk_flags
{
uint32_t value;
uint32_t value = 0;
struct
{
uint32_t has_mcsh : 1;
@@ -112,42 +112,42 @@ struct ENTRY_MODF
};
struct MapChunkHeader {
uint32_t flags;
uint32_t flags = 0;
uint32_t ix;
uint32_t iy;
uint32_t nLayers;
uint32_t nDoodadRefs;
uint32_t ofsHeight;
uint32_t ofsNormal;
uint32_t ofsLayer;
uint32_t ofsRefs;
uint32_t ofsAlpha;
uint32_t sizeAlpha;
uint32_t ofsShadow;
uint32_t sizeShadow;
uint32_t areaid;
uint32_t nMapObjRefs;
uint32_t holes;
std::uint16_t doodadMapping[8];
std::uint8_t doodadStencil[8];
uint32_t ofsSndEmitters;
uint32_t nSndEmitters;
uint32_t ofsLiquid;
uint32_t sizeLiquid;
uint32_t nLayers = 0;
uint32_t nDoodadRefs = 0;
uint32_t ofsHeight = 0;
uint32_t ofsNormal = 0;
uint32_t ofsLayer = 0;
uint32_t ofsRefs = 0;
uint32_t ofsAlpha = 0;
uint32_t sizeAlpha = 0;
uint32_t ofsShadow = 0;
uint32_t sizeShadow = 0;
uint32_t areaid = 0;
uint32_t nMapObjRefs = 0;
uint32_t holes = 0;
std::uint16_t doodadMapping[8]{ 0 };
std::uint8_t doodadStencil[8]{ 0 };
uint32_t ofsSndEmitters = 0;
uint32_t nSndEmitters = 0;
uint32_t ofsLiquid = 0;
uint32_t sizeLiquid = 0;
float zpos;
float xpos;
float ypos;
uint32_t ofsMCCV;
uint32_t unused1;
uint32_t unused2;
uint32_t ofsMCCV = 0;
uint32_t unused1 = 0;
uint32_t unused2 = 0;
};
struct MCCV
{
uint32_t textureID;
uint32_t flags;
uint32_t ofsAlpha;
uint32_t effectID;
uint32_t textureID = 0;
uint32_t flags = 0;
uint32_t ofsAlpha = 0;
uint32_t effectID = 0;
};
struct MCLYFlags
@@ -166,9 +166,9 @@ struct MCLYFlags
struct ENTRY_MCLY
{
uint32_t textureID;
uint32_t flags;
uint32_t ofsAlpha;
uint32_t textureID = 0;
uint32_t flags = 0;
uint32_t ofsAlpha = 0;
uint32_t effectID = 0xFFFF; // default value, see https://wowdev.wiki/ADT/v18#MCLY_sub-chunk
};

View File

@@ -190,7 +190,7 @@ private:
unsigned _chunk_update_flags;
// MHDR:
int mFlags;
int mFlags = 0;
bool mBigAlpha;
// Data to be loaded and later unloaded.

View File

@@ -75,6 +75,7 @@
#include <QCursor>
#include <QFileDialog>
#include <QProgressDialog>
#include <QClipboard>
#include <algorithm>
#include <cmath>
@@ -1102,6 +1103,21 @@ void MapView::setupFileMenu()
ADD_ACTION (file_menu, "Save current tile", "Ctrl+Shift+S", [this] { save(save_mode::current); emit saved();});
ADD_ACTION (file_menu, "Save changed tiles", QKeySequence::Save, [this] { save(save_mode::changed); emit saved(); });
ADD_ACTION (file_menu, "Save all tiles", "Ctrl+Shift+A", [this] { save(save_mode::all); emit saved(); });
ADD_ACTION(file_menu, "Generate new WDL", "", [this]
{
QMessageBox prompt;
prompt.setIcon(QMessageBox::Warning);
prompt.setWindowFlags(Qt::WindowStaysOnTopHint);
prompt.setText(std::string("Warning!\nThis will attempt to load all tiles in the map to generate a new WDL."
"\nThis is likely to crash if there is any issue with any tile, it is recommended that you save your work first. Only use this if you really need a fresh WDL.").c_str());
prompt.setInformativeText(std::string("Are you sure ?").c_str());
prompt.setStandardButtons(QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::No);
prompt.setDefaultButton(QMessageBox::No);
bool answer = prompt.exec() == QMessageBox::StandardButton::Yes;
if (answer)
_world->horizon.save_wdl(_world.get(), true);
}
);
ADD_ACTION ( file_menu
, "Reload tile"
@@ -1138,17 +1154,22 @@ void MapView::setupFileMenu()
}
);
ADD_ACTION ( file_menu
, "Write coordinates to port.txt"
ADD_ACTION(file_menu
, "Write coordinates to port.txt and copy to clipboard"
, Qt::Key_G
, [this]
{
std::stringstream port_command;
port_command << ".go XYZ " << (ZEROPOINT - _camera.position.z) << " " << (ZEROPOINT - _camera.position.x) << " " << _camera.position.y << " " << _world->getMapID();
std::ofstream f("ports.txt", std::ios_base::app);
f << "Map: " << gAreaDB.getAreaName(_world->getAreaID (_camera.position)) << " on ADT " << std::floor(_camera.position.x / TILESIZE) << " " << std::floor(_camera.position.z / TILESIZE) << std::endl;
f << "Trinity:" << std::endl << ".go " << (ZEROPOINT - _camera.position.z) << " " << (ZEROPOINT - _camera.position.x) << " " << _camera.position.y << " " << _world->getMapID() << std::endl;
f << "ArcEmu:" << std::endl << ".worldport " << _world->getMapID() << " " << (ZEROPOINT - _camera.position.z) << " " << (ZEROPOINT - _camera.position.x) << " " << _camera.position.y << " " << std::endl << std::endl;
f << "Trinity/AC:" << std::endl << port_command.str() << std::endl;
// f << "ArcEmu:" << std::endl << ".worldport " << _world->getMapID() << " " << (ZEROPOINT - _camera.position.z) << " " << (ZEROPOINT - _camera.position.x) << " " << _camera.position.y << " " << std::endl << std::endl;
f.close();
QClipboard* clipboard = QGuiApplication::clipboard();
clipboard->setText(port_command.str().c_str(), QClipboard::Clipboard);
}
);
}
@@ -5074,6 +5095,9 @@ void MapView::wheelEvent (QWheelEvent* event)
void MapView::mouseReleaseEvent (QMouseEvent* event)
{
makeCurrent();
OpenGL::context::scoped_setter const _(::gl, context());
switch (event->button())
{
case Qt::LeftButton:
@@ -5206,6 +5230,9 @@ void MapView::save(save_mode mode)
case save_mode::changed: _world->mapIndex.saveChanged(_world.get()); break;
case save_mode::all: _world->mapIndex.saveall(_world.get()); break;
}
// write wdl, we update wdl data prior in the mapIndex saving fucntions above
_world->horizon.save_wdl(_world.get());
NOGGIT_ACTION_MGR->purge();
AsyncLoader::instance().reset_object_fail();

View File

@@ -27,6 +27,9 @@ liquid_layer::liquid_layer(ChunkWater* chunk, glm::vec3 const& base, float heigh
, pos(base)
, _chunk(chunk)
{
if (!gLiquidTypeDB.CheckIfIdExists(_liquid_id))
_liquid_id = 1;
for (int z = 0; z < 9; ++z)
{
for (int x = 0; x < 9; ++x)
@@ -54,6 +57,9 @@ liquid_layer::liquid_layer(ChunkWater* chunk, glm::vec3 const& base, mclq& liqui
, pos(base)
, _chunk(chunk)
{
if (!gLiquidTypeDB.CheckIfIdExists(_liquid_id))
_liquid_id = 1;
changeLiquidID(_liquid_id);
for (int z = 0; z < 8; ++z)
@@ -107,6 +113,10 @@ liquid_layer::liquid_layer(ChunkWater* chunk
, pos(base)
, _chunk(chunk)
{
// check if liquid id is valid or some downported maps will crash
if (!gLiquidTypeDB.CheckIfIdExists(_liquid_id))
_liquid_id = 1;
int offset = 0;
for (int z = 0; z < info.height; ++z)
{

View File

@@ -5,11 +5,13 @@
#include <noggit/Log.h>
#include <noggit/application/NoggitApplication.hpp>
#include <noggit/map_index.hpp>
#include <noggit/MapTile.h>
#include <noggit/World.h>
#include <opengl/context.hpp>
#include <opengl/context.inl>
#include <sstream>
#include <bitset>
struct color
{
@@ -126,10 +128,37 @@ map_horizon::map_horizon(const std::string& basename, const MapIndex * const ind
}
// todo: handle those too ?
case 'MWMO':
case 'MWID':
case 'MODF':
{
{
char const* lCurPos = reinterpret_cast<char const*>(wdl_file.getPointer());
char const* lEnd = lCurPos + size;
while (lCurPos < lEnd)
{
mWMOFilenames.push_back(BlizzardArchive::ClientData::normalizeFilenameInternal(std::string(lCurPos)));
lCurPos += strlen(lCurPos) + 1;
}
}
wdl_file.seekRelative(size);
break;
}
case 'MWID':
wdl_file.seekRelative(size);
break;
// TODO
case 'MODF':
{
wdl_file.seekRelative(size);
break;
// {
// ENTRY_MODF const* modf_ptr = reinterpret_cast<ENTRY_MODF const*>(wdl_file.getPointer());
// for (unsigned int i = 0; i < size / sizeof(ENTRY_MODF); ++i)
// {
// lWMOInstances.push_back(modf_ptr[i]);
// }
// }
// break;
}
case 'MAOF':
{
assert(size == 64 * 64 * sizeof(uint32_t));
@@ -159,9 +188,18 @@ map_horizon::map_horizon(const std::string& basename, const MapIndex * const ind
//! \todo There also is MAHO giving holes into this heightmap.
wdl_file.read(_tiles[y][x]->height_17, 17 * 17 * sizeof(int16_t));
wdl_file.read(_tiles[y][x]->height_16, 16 * 16 * sizeof(int16_t));
}
wdl_file.read(&fourcc, 4);
if (fourcc == 'MAHO')
{
wdl_file.read(&size, 4);
assert(size == 0x20);
wdl_file.read(_tiles[y][x]->holes, 16 * sizeof(int16_t));
}
}
}
done = true;
break;
}
@@ -174,21 +212,26 @@ map_horizon::map_horizon(const std::string& basename, const MapIndex * const ind
wdl_file.close();
_qt_minimap = QImage (16 * 64, 16 * 64, QImage::Format_ARGB32);
_qt_minimap.fill (Qt::transparent);
set_minimap(index);
}
for (size_t y (0); y < 64; ++y)
void map_horizon::set_minimap(const MapIndex* const index)
{
_qt_minimap = QImage(16 * 64, 16 * 64, QImage::Format_ARGB32);
_qt_minimap.fill(Qt::transparent);
for (size_t y(0); y < 64; ++y)
{
for (size_t x (0); x < 64; ++x)
for (size_t x(0); x < 64; ++x)
{
if (_tiles[y][x])
{
//! \todo There also is a second heightmap appended which has additional 16*16 pixels.
//! \todo There also is MAHO giving holes into this heightmap.
for (size_t j (0); j < 16; ++j)
for (size_t j(0); j < 16; ++j)
{
for (size_t i (0); i < 16; ++i)
for (size_t i(0); i < 16; ++i)
{
//! \todo R and B are inverted here
_qt_minimap.setPixel(x * 16 + i, y * 16 + j, color_for_height(_tiles[y][x]->height_17[j][i]));
@@ -210,6 +253,203 @@ map_horizon::map_horizon(const std::string& basename, const MapIndex * const ind
}
}
Noggit::map_horizon_tile* map_horizon::get_horizon_tile(int y, int x)
{
return _tiles[y][x].get();
}
int16_t map_horizon::getWdlheight(MapTile* tile, float x, float y)
{
int cx = std::min(std::max(static_cast<int>(x / CHUNKSIZE), 0), 15);
int cy = std::min(std::max(static_cast<int>(y / CHUNKSIZE), 0), 15);
x -= cx * CHUNKSIZE;
y -= cy * CHUNKSIZE;
int row = static_cast<int>(y / (UNITSIZE * 0.5f) + 0.5f);
int col = static_cast<int>((x - UNITSIZE * 0.5f * (row % 2)) / UNITSIZE + 0.5f);
bool inner = (row % 2) == 1;
if (row < 0 || col < 0 || row > 16 || col >(inner ? 8 : 9))
return 0;
// truncate and clamp the float value
auto chunk = tile->getChunk(cx, cy);
// float height = heights[cy * 16 + cx][17 * (row / 2) + (inner ? 9 : 0) + col];
float height = chunk->getHeightmap()[17 * (row / 2) + (inner ? 9 : 0) + col].y;
return std::min(std::max(static_cast<int16_t>(height), static_cast<int16_t>(SHRT_MIN)), static_cast<int16_t>(SHRT_MAX));
}
void map_horizon::update_horizon_tile(MapTile* mTile)
{
auto tile_index = mTile->index;
// calculate the heightmap as a short array
float x, y;
for (int i = 0; i < 17; i++)
{
for (int j = 0; j < 17; j++)
{
// outer - correct
x = j * CHUNKSIZE;
y = i * CHUNKSIZE;
if (!_tiles[tile_index.z][tile_index.x].get()) // tile has not been initialised
// continue;
{
_tiles[tile_index.z][tile_index.x] = std::make_unique<map_horizon_tile>();
// do we need to use memcpy as well ?
}
// only works for initialised
_tiles[tile_index.z][tile_index.x].get()->height_17[i][j] = getWdlheight(mTile, x, y);
// inner - close enough; correct values appear to use some form of averaging
if (i < 16 && j < 16)
_tiles[tile_index.z][tile_index.x].get()->height_16[i][j] = getWdlheight(mTile, x + CHUNKSIZE / 2.0f, y + CHUNKSIZE / 2.0f);
}
}
// Holes
for (int i = 0; i < 16; ++i)
{
std::bitset<16>wdlHoleMask(0);
for (int j = 0; j < 16; ++j)
{
auto chunk = mTile->getChunk(j, i);
// the ordering seems to be : short array = Y axis, flags values = X axis and the values are for a whole chunk.
std::bitset<16> holeBits(chunk->getHoleMask());
if (holeBits.count() == 16) // if all holes are set in a chunk
wdlHoleMask.set(j, true);
}
_tiles[tile_index.z][tile_index.x].get()->holes[i] = static_cast<int16_t>(wdlHoleMask.to_ulong());
}
}
void map_horizon::save_wdl(World* world, bool regenerate)
{
world->wait_for_all_tile_updates();
std::stringstream filename;
filename << "World\\Maps\\" << world->basename << "\\" << world->basename << ".wdl";
//Log << "Saving WDL \"" << filename << "\"." << std::endl;
sExtendableArray wdlFile = sExtendableArray();
int curPos = 0;
// MVER
// {
wdlFile.Extend(8 + 0x4);
SetChunkHeader(wdlFile, curPos, 'MVER', 4);
// MVER data
*(wdlFile.GetPointer<int>(8)) = 18; // write version 18
curPos += 8 + 0x4;
// }
// MWMO
// {
wdlFile.Extend(8);
SetChunkHeader(wdlFile, curPos, 'MWMO', 0);
curPos += 8;
// }
// MWID
// {
wdlFile.Extend(8);
SetChunkHeader(wdlFile, curPos, 'MWID', 0);
curPos += 8;
// }
// TODO : MODF
// {
wdlFile.Extend(8);
SetChunkHeader(wdlFile, curPos, 'MODF', 0);
curPos += 8;
// }
//uint32_t mare_offsets[64][64] = { 0 };
// MAOF
// {
wdlFile.Extend(8);
SetChunkHeader(wdlFile, curPos, 'MAOF', 64 * 64 * 4);
curPos += 8;
wdlFile.Extend(64 * 64 * 4);
uint mareoffset = curPos + 64 * 64 * 4;
for (int y = 0; y < 64; ++y)
{
for (int x = 0; x < 64; ++x)
{
TileIndex index(x, y);
bool has_tile = world->mapIndex.hasTile(index);
// write offset in MAOF entry
*(wdlFile.GetPointer<uint>(curPos)) = has_tile ? mareoffset : 0;
if (has_tile)
{
// MARE Header
// {
wdlFile.Extend(8);
SetChunkHeader(wdlFile, mareoffset, 'MARE', (2 * (17 * 17)) + (2 * (16 * 16))); // outer heights+inner heights
mareoffset += 8;
// this might be invalid if map had no WDL
Noggit::map_horizon_tile* horizon_tile = get_horizon_tile(y, x);
// laod tile and extract WDL data
if (!horizon_tile || regenerate)
{
bool unload = !world->mapIndex.tileLoaded(index) && !world->mapIndex.tileAwaitingLoading(index);
MapTile* mTile = world->mapIndex.loadTile(index);
if (mTile)
mTile->wait_until_loaded();
update_horizon_tile(mTile);
if (unload)
world->mapIndex.unloadTile(index);
auto test = get_horizon_tile(y, x);
horizon_tile = get_horizon_tile(y, x);
}
if (!horizon_tile)
{
return; // failed to generate data somehow
LogError << "Failed to generate the WDL file." << std::endl;
}
wdlFile.Insert(mareoffset, sizeof(Noggit::map_horizon_tile::height_17), reinterpret_cast<char*>(&horizon_tile->height_17));
mareoffset += sizeof(Noggit::map_horizon_tile::height_17);
wdlFile.Insert(mareoffset, sizeof(Noggit::map_horizon_tile::height_16), reinterpret_cast<char*>(&horizon_tile->height_16));
mareoffset += sizeof(Noggit::map_horizon_tile::height_16);
// MAHO (maparea holes) MAHO was added in WOTLK ?
// {
wdlFile.Extend(8);
SetChunkHeader(wdlFile, mareoffset, 'MAHO', (2 * 16)); // 1 hole mask for each chunk
mareoffset += 8;
wdlFile.Extend(32);
for (int i = 0; i < 16; ++i)
{
wdlFile.Insert(mareoffset, 2, (char*)&horizon_tile->holes[i]);
mareoffset += 2;
}
}
curPos += 4;
}
}
BlizzardArchive::ClientFile f(filename.str(), Noggit::Application::NoggitApplication::instance()->clientData(),
BlizzardArchive::ClientFile::NEW_FILE);
f.setBuffer(wdlFile.data);
f.save();
f.close();
set_minimap(&world->mapIndex);
}
map_horizon::minimap::minimap(const map_horizon& horizon)
{
std::vector<uint32_t> texture(1024 * 1024);

View File

@@ -15,6 +15,9 @@
#include <memory>
class MapIndex;
class MapTile;
class MapView;
class World;
namespace Noggit
{
@@ -23,6 +26,7 @@ struct map_horizon_tile
{
int16_t height_17[17][17];
int16_t height_16[16][16];
int16_t holes[16];
};
struct map_horizon_batch
@@ -76,11 +80,24 @@ public:
map_horizon(const std::string& basename, const MapIndex * const index);
void set_minimap(const MapIndex* const index);
Noggit::map_horizon_tile* get_horizon_tile(int y, int x);
QImage _qt_minimap;
void update_horizon_tile(MapTile* mTile);
void save_wdl(World* world, bool regenerate = false);
private:
int16_t getWdlheight(MapTile* tile, float x, float y);
std::string _filename;
std::vector<std::string> mWMOFilenames;
// std::vector<ENTRY_MODF> lWMOInstances;
std::unique_ptr<map_horizon_tile> _tiles[64][64];
};

View File

@@ -177,6 +177,7 @@ void MapIndex::saveall (World* world)
for (MapTile* tile : loaded_tiles())
{
world->horizon.update_horizon_tile(tile);
tile->saveTile(world);
tile->changed = false;
}
@@ -462,6 +463,7 @@ void MapIndex::saveTile(const TileIndex& tile, World* world, bool save_unloaded)
if (tileLoaded(tile))
{
saveMaxUID();
world->horizon.update_horizon_tile(mTiles[tile.z][tile.x].tile.get());
mTiles[tile.z][tile.x].tile->saveTile(world);
}
}
@@ -516,6 +518,7 @@ void MapIndex::saveChanged (World* world, bool save_unloaded)
{
if (tile->changed.load())
{
world->horizon.update_horizon_tile(tile);
tile->saveTile(world);
tile->changed = false;
}
@@ -1205,3 +1208,111 @@ void MapIndex::set_basename(const std::string &pBasename)
}
}
}
void MapIndex::create_empty_wdl()
{
// for new map creation, creates a new WDL with all heights as 0
std::stringstream filename;
filename << "World\\Maps\\" << basename << "\\" << basename << ".wdl"; // mapIndex.basename ?
//Log << "Saving WDL \"" << filename << "\"." << std::endl;
sExtendableArray wdlFile = sExtendableArray();
int curPos = 0;
// MVER
// {
wdlFile.Extend(8 + 0x4);
SetChunkHeader(wdlFile, curPos, 'MVER', 4);
// MVER data
*(wdlFile.GetPointer<int>(8)) = 18; // write version 18
curPos += 8 + 0x4;
// }
// MWMO
// {
wdlFile.Extend(8);
SetChunkHeader(wdlFile, curPos, 'MWMO', 0);
curPos += 8;
// }
// MWID
// {
wdlFile.Extend(8);
SetChunkHeader(wdlFile, curPos, 'MWID', 0);
curPos += 8;
// }
// MODF
// {
wdlFile.Extend(8);
SetChunkHeader(wdlFile, curPos, 'MODF', 0);
curPos += 8;
// }
uint32_t mare_offsets[4096] = { 0 }; // [64][64];
// MAOF
// {
wdlFile.Extend(8);
SetChunkHeader(wdlFile, curPos, 'MAOF', 64 * 64 * 4);
curPos += 8;
uint32_t mareoffset = curPos + 64 * 64 * 4;
for (int y = 0; y < 64; ++y)
{
for (int x = 0; x < 64; ++x)
{
TileIndex index(x, y);
bool has_tile = hasTile(index);
// if (tile_exists)
if (has_tile) // TODO check if tile exists
{
// write offset in MAOF entry
wdlFile.Insert(curPos, 4, (char*)&mareoffset);
mare_offsets[y * 64 + x] = mareoffset;
mareoffset += 1138; // mare + maho
}
else
wdlFile.Extend(4);
curPos += 4;
}
}
for (auto offset : mare_offsets)
{
if (!offset)
continue;
// MARE
// {
wdlFile.Extend(8);
SetChunkHeader(wdlFile, curPos, 'MARE', (2 * (17 * 17)) + (2 * (16 * 16))); // outer heights+inner heights
curPos += 8;
// write inner and outer heights
wdlFile.Extend((2 * (17 * 17)) + (2 * (16 * 16)));
curPos += (2 * (17 * 17)) + (2 * (16 * 16));
// }
// MAHO (maparea holes)
// {
wdlFile.Extend(8);
SetChunkHeader(wdlFile, curPos, 'MAHO', 2 * 16); // 1 hole mask for each chunk
curPos += 8;
wdlFile.Extend(32);
curPos += 32;
}
BlizzardArchive::ClientFile f(filename.str(), Noggit::Application::NoggitApplication::instance()->clientData(),
BlizzardArchive::ClientFile::NEW_FILE);
f.setBuffer(wdlFile.data);
f.save();
f.close();
}

View File

@@ -186,6 +186,8 @@ public:
void set_basename(const std::string& pBasename);
void create_empty_wdl();
void enterTile(const TileIndex& tile);
MapTile *loadTile(const TileIndex& tile, bool reloading = false);

View File

@@ -408,7 +408,7 @@ void Square::setup_buffers()
}
void Cylinder::draw(glm::mat4x4 const& mvp, glm::vec3 const& pos, const glm::vec4 color, float radius, int precision, World* world, int height)
/*void Cylinder::draw(glm::mat4x4 const& mvp, glm::vec3 const& pos, const glm::vec4 color, float radius, int precision, World* world, int height)
{
if (!_buffers_are_setup)
{
@@ -501,4 +501,156 @@ void Square::setup_buffers()
}
_buffers_are_setup = true;
}*/
void Line::initSpline()
{
draw(glm::mat4x4{},
std::vector<glm::vec3>{ {}, {} },
glm::vec4{},
false);
}
void Line::draw(glm::mat4x4 const& mvp
, std::vector<glm::vec3> const points
, glm::vec4 const& color
, bool spline
)
{
if (points.size() < 2)
return;
if (!spline || points.size() == 2)
{
setup_buffers(points);
}
else
{
initSpline();
setup_buffers_interpolated(points);
}
OpenGL::Scoped::use_program line_shader{ *_program.get() };
line_shader.uniform("model_view_projection", mvp);
line_shader.uniform("color", color);
OpenGL::Scoped::vao_binder const _(_vao[0]);
gl.drawElements(GL_LINE_STRIP, _indices_vbo, _indice_count, GL_UNSIGNED_SHORT, nullptr);
}
void Line::setup_buffers(std::vector<glm::vec3> const points)
{
_vao.upload();
_buffers.upload();
std::vector<glm::vec3> vertices = points;
std::vector<std::uint16_t> indices;
for (int i = 0; i < points.size(); ++i)
{
indices.push_back(i);
}
setup_shader(vertices, indices);
}
void Line::setup_buffers_interpolated(std::vector<glm::vec3> const points)
{
const float tension = 0.5f;
std::vector<glm::vec3> tempPoints;
tempPoints.push_back(points[0]);
for (auto const& p : points)
tempPoints.push_back(p);
tempPoints.push_back(points[points.size() - 1]);
std::vector<glm::vec3> vertices;
std::vector<std::uint16_t> indices;
for (int i = 1; i < tempPoints.size() - 2; i++)
{
auto s = tension * 2.f;
auto p0 = tempPoints[i - 1];
auto p1 = tempPoints[i + 0];
auto p2 = tempPoints[i + 1];
auto p3 = tempPoints[i + 2];
glm::vec3 m1(
(p2.x - p0.x) / s,
(p2.y - p0.y) / s,
(p2.z - p0.z) / s
);
glm::vec3 m2(
(p3.x - p1.x) / s,
(p3.y - p1.y) / s,
(p3.z - p1.z) / s
);
vertices.push_back(interpolate(0, p1, p2, m1, m2));
for (float t = 0.01f; t < 1.f; t += 0.01f)
vertices.push_back(interpolate(t, p1, p2, m1, m2));
vertices.push_back(interpolate(1, p1, p2, m1, m2));
}
for (int i = 0; i < vertices.size(); ++i)
{
indices.push_back(i);
}
setup_shader(vertices, indices);
}
glm::vec3 Line::interpolate(float t, glm::vec3 p0, glm::vec3 p1, glm::vec3 m0, glm::vec3 m1)
{
auto c = 2 * t * t * t - 3 * t * t;
auto c0 = c + 1;
auto c1 = t * t * t - 2 * t * t + t;
auto c2 = -c;
auto c3 = t * t * t - t * t;
return (c0 * p0 + c1 * m0 + c2 * p1 + c3 * m1);
}
void Line::setup_shader(std::vector<glm::vec3> vertices, std::vector<std::uint16_t> indices)
{
_indice_count = (int)indices.size();
_program.reset(new OpenGL::program(
{
{ GL_VERTEX_SHADER, OpenGL::shader::src_from_qrc("line_vs") },
{ GL_FRAGMENT_SHADER, OpenGL::shader::src_from_qrc("line_fs") }
}
));
gl.bufferData<GL_ARRAY_BUFFER, glm::vec3>(_vertices_vbo, vertices, GL_STATIC_DRAW);
gl.bufferData<GL_ELEMENT_ARRAY_BUFFER, std::uint16_t>(_indices_vbo, indices, GL_STATIC_DRAW);
OpenGL::Scoped::index_buffer_manual_binder indices_binder(_indices_vbo);
OpenGL::Scoped::use_program shader(*_program.get());
{
OpenGL::Scoped::vao_binder const _(_vao[0]);
OpenGL::Scoped::buffer_binder<GL_ARRAY_BUFFER> const vertices_binder(_vertices_vbo);
shader.attrib("position", 3, GL_FLOAT, GL_FALSE, 0, 0);
indices_binder.bind();
}
_buffers_are_setup = true;
}
void Line::unload()
{
_vao.unload();
_buffers.unload();
_program.reset();
_buffers_are_setup = false;
}

View File

@@ -136,7 +136,7 @@ namespace Noggit::Rendering::Primitives
std::unique_ptr<OpenGL::program> _program;
};
class Cylinder
/*class Cylinder
{
public:
void draw(glm::mat4x4 const& mvp, glm::vec3 const& pos, const glm::vec4 color, float radius, int precision, World* world, int height = 10);
@@ -147,6 +147,30 @@ namespace Noggit::Rendering::Primitives
void setup_buffers(int precision, World* world, int height);
int _indice_count = 0;
OpenGL::Scoped::deferred_upload_vertex_arrays<1> _vao;
OpenGL::Scoped::deferred_upload_buffers<2> _buffers;
GLuint const& _vertices_vbo = _buffers[0];
GLuint const& _indices_vbo = _buffers[1];
std::unique_ptr<OpenGL::program> _program;
};*/
class Line
{
public:
void initSpline();
void draw(glm::mat4x4 const& mvp, std::vector<glm::vec3> const points, glm::vec4 const& color, bool spline);
void unload();
private:
bool _buffers_are_setup = false;
void setup_buffers(std::vector<glm::vec3> const points);
void setup_buffers_interpolated(std::vector<glm::vec3> const points);
glm::vec3 interpolate(float t, glm::vec3 p0, glm::vec3 p1, glm::vec3 m0, glm::vec3 m1);
int _indice_count = 0;
void setup_shader(std::vector<glm::vec3> vertices, std::vector<std::uint16_t> indices);
OpenGL::Scoped::deferred_upload_vertex_arrays<1> _vao;
OpenGL::Scoped::deferred_upload_buffers<2> _buffers;
GLuint const& _vertices_vbo = _buffers[0];

View File

@@ -1189,7 +1189,7 @@ void WorldRender::unload()
_cursor_render.unload();
_sphere_render.unload();
_square_render.unload();
_cylinder_render.unload();
_line_render.unload();
_horizon_render.reset();
_liquid_texture_manager.unload();

View File

@@ -128,7 +128,7 @@ namespace Noggit::Rendering
Noggit::CursorRender _cursor_render;
Noggit::Rendering::Primitives::Sphere _sphere_render;
Noggit::Rendering::Primitives::Square _square_render;
Noggit::Rendering::Primitives::Cylinder _cylinder_render;
Noggit::Rendering::Primitives::Line _line_render;
// buffers
OpenGL::Scoped::deferred_upload_buffers<8> _buffers;

View File

@@ -0,0 +1,10 @@
#version 330 core
uniform vec4 color;
out vec4 out_color;
void main()
{
out_color = color;
}

View File

@@ -0,0 +1,10 @@
#version 330 core
in vec4 position;
uniform mat4 model_view_projection;
void main()
{
gl_Position = model_view_projection * position;
}

View File

@@ -1,8 +1,8 @@
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
#version 410 core
const double TILESIZE = 533.33333;
const double CHUNKSIZE = TILESIZE / 16.0;
const float TILESIZE = 533.33333;
const float CHUNKSIZE = 533.33333 / 16.0;
in vec2 position;
in vec2 texcoord;
@@ -160,25 +160,25 @@ void main()
instanceID = base_instance + (t_x * 16 + t_z);
vec4 normal_pos = texelFetch(heightmap, ivec2(gl_VertexID, instanceID), 0);
dvec3 pos = dvec3(double(instances[instanceID].ChunkXZ_TileXZ.z * TILESIZE)
+ double(instances[instanceID].ChunkXZ_TileXZ.x * CHUNKSIZE)
+ double(position.x)
, double(normal_pos.a)
, double(instances[instanceID].ChunkXZ_TileXZ.w * TILESIZE)
+ double(instances[instanceID].ChunkXZ_TileXZ.y * CHUNKSIZE)
+ double(position.y)
vec3 pos = vec3(instances[instanceID].ChunkXZ_TileXZ.z * TILESIZE
+ instances[instanceID].ChunkXZ_TileXZ.x * CHUNKSIZE
+ position.x
, normal_pos.a
, instances[instanceID].ChunkXZ_TileXZ.w * TILESIZE
+ instances[instanceID].ChunkXZ_TileXZ.y * CHUNKSIZE
+ position.y
);
bool is_hole = isHoleVertex(gl_VertexID, instances[instanceID].ChunkHoles_DrawImpass_TexLayerCount_CantPaint.r);
float NaN = makeNaN(1);
dvec4 pos_after_holecheck = (is_hole ? dvec4(NaN, NaN, NaN, 1.0) : dvec4(pos, 1.0));
gl_Position = projection * model_view * vec4(pos_after_holecheck);
vec4 pos_after_holecheck = (is_hole ? vec4(NaN, NaN, NaN, 1.0) : vec4(pos, 1.0));
gl_Position = projection * model_view * pos_after_holecheck;
vary_normal = normal_pos.rgb;
triangle_normal = normal_pos.rgb;
vary_position = vec3(pos);
vary_position = pos;
vary_mccv = texelFetch(mccv, ivec2(gl_VertexID, instanceID), 0).rgb;
vary_t0_uv = texcoord + animUVOffset(instances[instanceID].ChunkTexDoAnim.r,

View File

@@ -117,6 +117,9 @@ namespace Noggit
void texture_picker::updateSelection()
{
if (!_chunk)
return;
for (size_t index = 0; index < _chunk->texture_set->num(); ++index)
{
_labels[index]->unselect();

View File

@@ -531,6 +531,7 @@ namespace Noggit
layout->addRow("Zone Intro Music:", _zone_intro_music_button);
layout->addRow("Sound Ambience Day:", _sound_ambiance_day_button);
layout->addRow("Sound Ambience Night:", _sound_ambiance_night_button);
layout->addRow(new QLabel("If only day or night is set but not the other, the other will be saved as the same sound."));
layout->addRow(AdvancedOptionsBox);
layout->addRow(save_area_button);
@@ -757,12 +758,23 @@ namespace Noggit
// Just iterate the DBC to see if an entry with our settings already exists, if not create it.
// The reasoning for not having a selector/picker with the existing pairs is that it has less freedom, is harder to use and it's ugly if they don't have a name.
// This doesn't have the option to edit that entry for all its users though.
int soundambience_day = _sound_ambiance_day_button->property("id").toInt();
int soundambience_night = _sound_ambiance_night_button->property("id").toInt();
if (soundambience_day && !soundambience_night) // if day is set but not night, set night to day
soundambience_night = soundambience_day;
else if (!soundambience_day && soundambience_night) // night to day
soundambience_night = soundambience_day;
if (soundambience_day && soundambience_night) // check if both day and night are set
{
bool sound_ambiance_exists {false};
for (DBCFile::Iterator i = gSoundAmbienceDB.begin(); i != gSoundAmbienceDB.end(); ++i)
{
int day_id = i->getInt(SoundAmbienceDB::SoundEntry_day);
int night_id = i->getInt(SoundAmbienceDB::SoundEntry_night);
if (day_id == _sound_ambiance_day_button->property("id").toInt() && night_id == _sound_ambiance_night_button->property("id").toInt())
if (day_id == soundambience_day && night_id == soundambience_night)
{
record.write(AreaDB::SoundAmbience, i->getInt(SoundAmbienceDB::ID));
sound_ambiance_exists = true;
@@ -771,14 +783,19 @@ namespace Noggit
}
if (!sound_ambiance_exists)
{
// create new sond entry record
// create new sond entry record with the two ids
auto new_id = gSoundAmbienceDB.getEmptyRecordID();
auto new_record = gSoundAmbienceDB.addRecord(new_id);
new_record.write(SoundAmbienceDB::SoundEntry_day, _sound_ambiance_day_button->property("id").toInt());
new_record.write(SoundAmbienceDB::SoundEntry_night, _sound_ambiance_night_button->property("id").toInt());
new_record.write(SoundAmbienceDB::SoundEntry_day, soundambience_day);
new_record.write(SoundAmbienceDB::SoundEntry_night, soundambience_night);
gSoundAmbienceDB.save();
record.write(AreaDB::SoundAmbience, new_id);
}
}
else
record.write(AreaDB::SoundAmbience, 0); // if night or day isn't set, set to 0
record.write(AreaDB::ZoneMusic, _zone_music_button->property("id").toInt());
record.write(AreaDB::ZoneIntroMusicTable, _zone_intro_music_button->property("id").toInt());
@@ -786,6 +803,13 @@ namespace Noggit
record.write(AreaDB::ExplorationLevel, _exploration_level_spinbox->value());
_area_name->toRecord(record, AreaDB::Name);
// update name in the tree
auto parent = static_cast<zone_id_browser*>(this->parentWidget());
auto item = parent->create_or_get_tree_widget_item(_area_id_label->text().toInt());
std::stringstream ss;
std::string areaName = record.getLocalizedString(AreaDB::Name);
ss << _area_id_label->text().toInt() << "-" << areaName;
item->setText(0, QString(ss.str().c_str()));
record.write(AreaDB::FactionGroup, _faction_group_combobox->currentIndex() * 2);
record.write(AreaDB::MinElevation, static_cast<float>(_min_elevation_spinbox->value()));
@@ -793,6 +817,8 @@ namespace Noggit
record.write(AreaDB::LightId, 0); // never used
gAreaDB.save();
load_area(_area_id_label->text().toInt()); // reload ui, especially for night/day ambience
}
}

View File

@@ -111,8 +111,21 @@ MapCreationWizard::MapCreationWizard(std::shared_ptr<Project::NoggitProject> pro
_map_settings = new QGroupBox("Map settings", this);
layout_right->addWidget(_map_settings);
auto map_settings_layout = new QFormLayout(_map_settings);
_map_settings->setLayout(map_settings_layout);
auto box_map_settings_layout = new QVBoxLayout(_map_settings);
_map_settings->setLayout(box_map_settings_layout);
_tabs = new QTabWidget(_map_settings);
auto map_settings_widget(new QWidget(this));
auto map_difficulty_widget(new QWidget(this));
_tabs->addTab(map_settings_widget, "Map Settings");
_tabs->addTab(map_difficulty_widget, "Map Difficulty Settings");
box_map_settings_layout->addWidget(_tabs);
auto map_settings_layout = new QFormLayout(map_settings_widget);
_directory = new QLineEdit(_map_settings);
map_settings_layout->addRow("Map directory:", _directory);
@@ -206,6 +219,33 @@ MapCreationWizard::MapCreationWizard(std::shared_ptr<Project::NoggitProject> pro
_max_players->setMaximum(std::numeric_limits<std::int32_t>::max());
map_settings_layout->addRow("Max players:",_max_players);
// difficulty tab
auto difficulty_settings_layout = new QFormLayout(map_difficulty_widget);
_map_settings->setLayout(difficulty_settings_layout);
_difficulty_type = new QComboBox(_map_settings);
difficulty_settings_layout->addRow("Difficulty Index", _difficulty_type);
_difficulty_req_message = new LocaleDBCEntry(_map_settings);
_difficulty_req_message->setDisabled(true); // disable them until they're actually saveable, only "display" it for now
difficulty_settings_layout->addRow("Requirement Message", _difficulty_req_message);
_difficulty_raid_duration = new QSpinBox(_map_settings);
_difficulty_raid_duration->setDisabled(true);
_difficulty_raid_duration->setRange(0, 7);
difficulty_settings_layout->addRow("Instance Duration(days)", _difficulty_raid_duration);
_difficulty_max_players = new QSpinBox(_map_settings);
_difficulty_max_players->setDisabled(true);
difficulty_settings_layout->addRow("Max Players", _difficulty_max_players);
_difficulty_string = new QLineEdit(_map_settings);
_difficulty_string->setDisabled(true);
difficulty_settings_layout->addRow("Difficulty String", _difficulty_string);
difficulty_settings_layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding));
// Bottom row
auto bottom_row_wgt = new QWidget(layout_right_holder);
auto btn_row_layout = new QHBoxLayout(layout_right_holder);
@@ -255,6 +295,10 @@ MapCreationWizard::MapCreationWizard(std::shared_ptr<Project::NoggitProject> pro
}
);
connect(_difficulty_type, qOverload<int>(&QComboBox::currentIndexChanged), [this](int index) {
selectMapDifficulty();
});
// Selection
QObject::connect
@@ -317,6 +361,40 @@ MapCreationWizard::MapCreationWizard(std::shared_ptr<Project::NoggitProject> pro
}
std::string MapCreationWizard::getDifficultyString()
{
if (_instance_type->itemData(_instance_type->currentIndex()).toInt() == 1 && _difficulty_max_players->value() == 5) // dungeon
{
if (_difficulty_type->currentIndex() == 0)
return "DUNGEON_DIFFICULTY_5PLAYER";
else
return "DUNGEON_DIFFICULTY_5PLAYER_HEROIC";
}
else if (_instance_type->itemData(_instance_type->currentIndex()).toInt() == 2)
{
switch (_difficulty_max_players->value())
{
case 10:
if (_difficulty_type->currentIndex() == 0)
return "RAID_DIFFICULTY_10PLAYER";
else
return "RAID_DIFFICULTY_10PLAYER_HEROIC";
case 20:
if (_difficulty_type->currentIndex() == 0)
return "RAID_DIFFICULTY_20PLAYER";
case 25:
// in BC 25men was difficulty 0, after the 10men mode in wrath it is difficulty 1
if (_difficulty_type->currentIndex() == (0 || 1)) // maybe instead check if a difficulty 25 already exists
return "RAID_DIFFICULTY_25PLAYER";
else
return "RAID_DIFFICULTY_25PLAYER_HEROIC";
case 40:
return "RAID_DIFFICULTY_40PLAYER";
}
}
return "";
}
void MapCreationWizard::selectMap(int map_id)
{
_is_new_record = false;
@@ -342,8 +420,29 @@ void MapCreationWizard::selectMap(int map_id)
auto expansionId = record.Columns["ExpansionID"].Value;
auto maxPlayers = record.Columns["MaxPlayers"].Value;
auto timeOffset = record.Columns["TimeOffset"].Value;
auto raidOffset = record.Columns["RaidOffset"].Value;
_world = new World(directoryName, map_id, Noggit::NoggitRenderContext::MAP_VIEW);
// check if map has a wdl and prompt to create a new one
std::stringstream filename;
filename << "World\\Maps\\" << _world->basename << "\\" << _world->basename << ".wdl";
if (!Application::NoggitApplication::instance()->clientData()->exists(filename.str()))
{
QMessageBox prompt;
prompt.setText(std::string("This map has no existing horizon data (.wdl file).").c_str());
prompt.setInformativeText(std::string("Do you want to generate a new .wdl file ?").c_str());
prompt.setStandardButtons(QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::No);
prompt.setDefaultButton(QMessageBox::Yes);
bool answer = prompt.exec() == QMessageBox::StandardButton::Yes;
if (answer)
{
_world->horizon.save_wdl(_world, true);
_world->horizon.set_minimap(&_world->mapIndex);
// _world = new World(directoryName, map_id, Noggit::NoggitRenderContext::MAP_VIEW); // refresh minimap
}
}
_minimap_widget->world(_world);
_directory->setText(QString::fromStdString(directoryName));
@@ -383,11 +482,60 @@ void MapCreationWizard::selectMap(int map_id)
_time_of_day_override->setValue(std::atoi(timeOffset.c_str()));
_expansion_id->setCurrentIndex(std::atoi(expansionId.c_str()));
//_raid_offset->setValue(record.getInt(64)); only ever used in 2 places? not sure what for
_raid_offset->setValue(std::atoi(raidOffset.c_str())); // only ever used in 2 places? not sure what for
_max_players->setValue(std::atoi(maxPlayers.c_str()));
_project->ClientDatabase->UnloadTable("Map");
auto difficulty_table = _project->ClientDatabase->LoadTable("MapDifficulty", readFileAsIMemStream);
auto iterator = difficulty_table.Records();
QSignalBlocker const difficulty_type_blocker(_difficulty_type);
_difficulty_type->clear();
while (iterator.HasRecords())
{
auto record = iterator.Next();
// auto difficulty_id = std::atoi(record.Columns["ID"].Value.c_str());
auto record_id = record.RecordId;
auto diff_mapId = std::atoi(record.Columns["MapID"].Value.c_str());
auto difficulty_type = std::atoi(record.Columns["Difficulty"].Value.c_str());
if (diff_mapId == map_id)
{
std::string diff_text = "Difficulty " + record.Columns["Difficulty"].Value;
_difficulty_type->insertItem(difficulty_type, diff_text.c_str(), QVariant(record_id));
}
}
_project->ClientDatabase->UnloadTable("MapDifficulty");
_difficulty_type->setCurrentIndex(0);
selectMapDifficulty();
}
void MapCreationWizard::selectMapDifficulty()
{
if (!_difficulty_type->count())
return;
auto selected_difficulty_id = _difficulty_type->itemData(_difficulty_type->currentIndex()).toInt();
if (!selected_difficulty_id)
return;
auto difficulty_table = _project->ClientDatabase->LoadTable("MapDifficulty", readFileAsIMemStream);
auto record = difficulty_table.Record(selected_difficulty_id);
//_difficulty_type;
_difficulty_req_message->fill(record, "Message_lang");
auto raid_duration = std::atoi(record.Columns["RaidDuration"].Value.c_str());
_difficulty_raid_duration->setValue(raid_duration / 60 / 60 / 24); // convert from seconds to days
_difficulty_max_players->setValue(std::atoi(record.Columns["MaxPlayers"].Value.c_str()));
_difficulty_string->setText(record.Columns["Difficultystring"].Value.c_str());
_project->ClientDatabase->UnloadTable("MapDifficulty");
}
void MapCreationWizard::wheelEvent(QWheelEvent* event)
@@ -458,11 +606,15 @@ void MapCreationWizard::saveCurrentEntry()
}
// Save ADTs and WDT to disk
// _world->mapIndex.create_empty_wdl();
_world->mapIndex.setBigAlpha(_is_big_alpha->isChecked());
_world->setBasename(_directory->text().toStdString());
_world->mapIndex.set_sort_models_by_size_class(_sort_by_size_cat->isChecked());
_world->mapIndex.saveChanged(_world, true);
_world->mapIndex.save();
_world->mapIndex.save(); // save wdt file
// create default wdl
if (_is_new_record)
_world->mapIndex.create_empty_wdl();
// Save Map.dbc record
DBCFile::Record record = _is_new_record ? gMapDB.addRecord(_cur_map_id) : gMapDB.getByID(_cur_map_id);

View File

@@ -97,6 +97,8 @@ namespace Noggit
int _selected_map;
QGroupBox* _map_settings;
QTabWidget* _tabs;
// Map settings
QLineEdit* _directory;
@@ -124,6 +126,13 @@ namespace Noggit
QSpinBox* _raid_offset;
QSpinBox* _max_players;
// map difficulty settings
QComboBox* _difficulty_type;
LocaleDBCEntry* _difficulty_req_message;
QSpinBox* _difficulty_raid_duration;
QSpinBox* _difficulty_max_players;
QLineEdit* _difficulty_string;
World* _world = nullptr;
bool _is_new_record = false;
@@ -131,7 +140,10 @@ namespace Noggit
QMetaObject::Connection _connection;
std::string getDifficultyString();
void selectMap(int map_id);
void selectMapDifficulty();
void saveCurrentEntry();
void discardChanges();

View File

@@ -10,7 +10,7 @@ namespace Noggit
CChangelog::CChangelog(QWidget* parent) :
QDialog(parent)
{
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
/*setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
ui = new ::Ui::Changelog;
ui->setupUi(this);
@@ -46,7 +46,7 @@ namespace Noggit
connect(ui->listWidget, &QListWidget::itemClicked, [&](QListWidgetItem *item)
{
OpenChangelog(item->data(1).toString());
});
});*/
}
void CChangelog::SelectFirst()

View File

@@ -30,17 +30,18 @@ NoggitProjectSelectionWindow::NoggitProjectSelectionWindow(Noggit::Application::
_ui->label_2->setStyleSheet("QLabel#title { font-size: 18px; padding: 0px; }");
_settings = new Noggit::Ui::settings(this);
_changelog = new Noggit::Ui::CChangelog(this);
//_changelog = new Noggit::Ui::CChangelog(this);
_load_project_component = std::make_unique<Component::LoadProjectComponent>();
_ui->settings_button->setIcon(Noggit::Ui::FontAwesomeIcon(Noggit::Ui::FontAwesome::Icons::cog));
_ui->settings_button->setIconSize(QSize(20,20));
_ui->changelog_button->setIcon(Noggit::Ui::FontAwesomeIcon(Noggit::Ui::FontAwesome::Icons::file));
_ui->changelog_button->setIconSize(QSize(20, 20));
_ui->changelog_button->setText(tr(" Changelog"));
_ui->changelog_button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
_ui->changelog_button->hide();
//_ui->changelog_button->setIcon(Noggit::Ui::FontAwesomeIcon(Noggit::Ui::FontAwesome::Icons::file));
//_ui->changelog_button->setIconSize(QSize(20, 20));
//_ui->changelog_button->setText(tr(" Changelog"));
//_ui->changelog_button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
Component::RecentProjectsComponent::buildRecentProjectsList(this);
@@ -50,11 +51,11 @@ NoggitProjectSelectionWindow::NoggitProjectSelectionWindow(Noggit::Application::
}
);
QObject::connect(_ui->changelog_button, &QToolButton::clicked, [&]()
/*QObject::connect(_ui->changelog_button, &QToolButton::clicked, [&]()
{
_changelog->SelectFirst();
_changelog->show();
});
});*/
QObject::connect(_ui->button_create_new_project, &QPushButton::clicked, [=, this]
{
@@ -142,7 +143,7 @@ NoggitProjectSelectionWindow::NoggitProjectSelectionWindow(Noggit::Application::
);
// !disable-update && !force-changelog
if (!_noggit_application->GetCommand(0) && !_noggit_application->GetCommand(1))
/*if (!_noggit_application->GetCommand(0) && !_noggit_application->GetCommand(1))
{
_updater = new Noggit::Ui::CUpdater(this);
@@ -151,13 +152,13 @@ NoggitProjectSelectionWindow::NoggitProjectSelectionWindow(Noggit::Application::
_updater->setModal(true);
_updater->show();
});
}
}*/
auto _set = new QSettings(this);
auto first_changelog = _set->value("first_changelog", false);
//auto first_changelog = _set->value("first_changelog", false);
// force-changelog
if (_noggit_application->GetCommand(1) || !first_changelog.toBool())
/*if (_noggit_application->GetCommand(1) || !first_changelog.toBool())
{
_changelog->setModal(true);
_changelog->show();
@@ -167,7 +168,7 @@ NoggitProjectSelectionWindow::NoggitProjectSelectionWindow(Noggit::Application::
_set->setValue("first_changelog", true);
_set->sync();
}
}
}*/
}

View File

@@ -48,8 +48,8 @@ namespace Noggit::Ui::Windows
::Ui::NoggitProjectSelectionWindow* _ui;
Noggit::Application::NoggitApplication* _noggit_application;
Noggit::Ui::settings* _settings;
Noggit::Ui::CUpdater* _updater;
Noggit::Ui::CChangelog* _changelog;
//Noggit::Ui::CUpdater* _updater;
//Noggit::Ui::CChangelog* _changelog;
std::unique_ptr<Noggit::Ui::Windows::NoggitWindow> _project_selection_page;
std::unique_ptr<Component::LoadProjectComponent> _load_project_component;

View File

@@ -8,7 +8,7 @@ namespace Noggit
CUpdater::CUpdater(QWidget* parent) :
QDialog(parent)
{
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
/*setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
ui = new ::Ui::Updater;
ui->setupUi(this);
@@ -36,7 +36,7 @@ namespace Noggit
QNetworkReply* reply = (new QNetworkAccessManager)->get(request);
connect(reply, SIGNAL(finished()), this, SLOT(GenerateOnlineMD5()));
GenerateLocalMD5();
GenerateLocalMD5();*/
}
QByteArray CUpdater::FileMD5(const QString& filename, QCryptographicHash::Algorithm algo)