Merge branch 'noggit-shadowlands' of https://gitlab.com/prophecy-rp/noggit-red into wmo-stuff
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
@@ -190,7 +190,7 @@ private:
|
||||
unsigned _chunk_update_flags;
|
||||
|
||||
// MHDR:
|
||||
int mFlags;
|
||||
int mFlags = 0;
|
||||
bool mBigAlpha;
|
||||
|
||||
// Data to be loaded and later unloaded.
|
||||
|
||||
@@ -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"
|
||||
@@ -1139,16 +1155,21 @@ void MapView::setupFileMenu()
|
||||
);
|
||||
|
||||
ADD_ACTION(file_menu
|
||||
, "Write coordinates to port.txt"
|
||||
, "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();
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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,6 +212,11 @@ map_horizon::map_horizon(const std::string& basename, const MapIndex * const ind
|
||||
|
||||
wdl_file.close();
|
||||
|
||||
set_minimap(index);
|
||||
}
|
||||
|
||||
void map_horizon::set_minimap(const MapIndex* const index)
|
||||
{
|
||||
_qt_minimap = QImage(16 * 64, 16 * 64, QImage::Format_ARGB32);
|
||||
_qt_minimap.fill(Qt::transparent);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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];
|
||||
};
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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];
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
10
src/noggit/rendering/glsl/line_frag.glsl
Normal file
10
src/noggit/rendering/glsl/line_frag.glsl
Normal file
@@ -0,0 +1,10 @@
|
||||
#version 330 core
|
||||
|
||||
uniform vec4 color;
|
||||
|
||||
out vec4 out_color;
|
||||
|
||||
void main()
|
||||
{
|
||||
out_color = color;
|
||||
}
|
||||
10
src/noggit/rendering/glsl/line_vert.glsl
Normal file
10
src/noggit/rendering/glsl/line_vert.glsl
Normal file
@@ -0,0 +1,10 @@
|
||||
#version 330 core
|
||||
|
||||
in vec4 position;
|
||||
|
||||
uniform mat4 model_view_projection;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = model_view_projection * position;
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user