Merge branch 'master' into 1.8-Protocol
This commit is contained in:
commit
4398156b2e
@ -29,5 +29,6 @@ worktycho
|
||||
xoft
|
||||
Yeeeeezus (Donated AlchemistVillage prefabs)
|
||||
Howaner
|
||||
Masy98
|
||||
|
||||
Please add yourself to this list if you contribute to MCServer.
|
||||
|
@ -1502,7 +1502,7 @@ function OnPlayerJoined(a_Player)
|
||||
-- Test composite chat chaining:
|
||||
a_Player:SendMessage(cCompositeChat()
|
||||
:AddTextPart("Hello, ")
|
||||
:AddUrlPart(a_Player:GetName(), "www.mc-server.org", "u@2")
|
||||
:AddUrlPart(a_Player:GetName(), "http://www.mc-server.org", "u@2")
|
||||
:AddSuggestCommandPart(", and welcome.", "/help", "u")
|
||||
:AddRunCommandPart(" SetDay", "/time set 0")
|
||||
)
|
||||
|
@ -1,209 +0,0 @@
|
||||
@echo off
|
||||
:: Nightbbuild2008.cmd
|
||||
:: This script is run every night to produce a new version of MCServer, backup its PDB files and upload the packages to web.
|
||||
:: When run without parameters, this script pauses at the end and waits for a keypress.
|
||||
:: To run in an automated scheduler, add any parameter to disable waiting for a keystroke
|
||||
::
|
||||
:: The sript creates a symbol store (a database of PDB files) that can be used as a single entry in MSVC's symbol path,
|
||||
:: then any executable / crashdump built by this script can be debugged and its symbols will be found automatically by MSVC,
|
||||
:: without the users needing to specify the build version or anything.
|
||||
:: In order to support pruning the symstore, a per-month store is created, so that old months can be removed when no longer needed.
|
||||
::
|
||||
:: This script expects a few tools on specific paths, you can pass the correct paths for your system as env vars "zip" and "vc"
|
||||
:: This script assumes that "git", "symstore" and "touch" are available on PATH.
|
||||
:: git comes from msysgit
|
||||
:: symstore comes from Microsoft's Debugging Tools for Windows
|
||||
:: touch comes from unxtools
|
||||
:: This script is locale-dependent, because it parses the output of "time" and "date" shell commands
|
||||
|
||||
|
||||
:: 7-zip executable (by default it should be on PATH):
|
||||
if %zip%a == a set zip=7z
|
||||
|
||||
:: Visual C++ compiler executable name:
|
||||
if %vc%a == a set vc="vcbuild.exe"
|
||||
|
||||
|
||||
|
||||
|
||||
:: Check that the required environment vars are available:
|
||||
if "a%ftppass%" == "a" (
|
||||
echo You need to set FTP password in the ftppass environment variable to upload the files
|
||||
goto haderror
|
||||
)
|
||||
if "a%ftpuser%" == "a" (
|
||||
echo You need to set FTP username in the ftpuser environment variable to upload the files
|
||||
goto haderror
|
||||
)
|
||||
if "a%ftpsite%" == "a" (
|
||||
echo You need to set FTP server in the ftpsite environment variable to upload the files
|
||||
goto haderror
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
:: Get the date and time into vars:
|
||||
:: This is locale-dependent!
|
||||
For /f "tokens=2-4 delims=/. " %%a in ('date /t') do (
|
||||
set MYYEAR=%%c
|
||||
set MYMONTH=%%b
|
||||
set MYDAY=%%a
|
||||
)
|
||||
For /f "tokens=1-2 delims=/:" %%a in ('time /t') do (set MYTIME=%%a_%%b)
|
||||
|
||||
echo Performing nightbuild of MC-Server
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
set DONOTPAUSE=y
|
||||
|
||||
:: Update the sources to the latest revision:
|
||||
git pull
|
||||
if errorlevel 1 goto haderror
|
||||
|
||||
|
||||
|
||||
:: Update the external plugins to the latest revision:
|
||||
git submodule update
|
||||
if errorlevel 1 goto haderror
|
||||
|
||||
|
||||
|
||||
|
||||
:: Get the Git commit ID into an environment var
|
||||
For /f "tokens=1 delims=/. " %%a in ('git log -1 --oneline --no-abbrev-commit') do (set COMMITID=%%a)
|
||||
if errorlevel 1 goto haderror
|
||||
|
||||
|
||||
|
||||
:: Test if the version is already present, using a "tagfile" that we create upon successful build
|
||||
set TAGFOLDER=Install\%MYYEAR%_%MYMONTH%\
|
||||
set TAGFILE=%TAGFOLDER%built_%COMMITID%.tag
|
||||
echo Tag file: %TAGFILE%
|
||||
if exist %TAGFILE% (
|
||||
echo Latest version already present, bailing out
|
||||
goto end
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
:: Configure the sources to use the MSVC2008 compiler:
|
||||
cmake -G "Visual Studio 9 2008" .
|
||||
if errorlevel 1 goto haderror
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
:: Update the Bindings:
|
||||
echo Updating Lua bindings
|
||||
del src\Bindings\Bindings.cpp
|
||||
del src\Bindings\Bindings.h
|
||||
set ALLTOLUA_WAIT=N
|
||||
cd src\Bindings
|
||||
call AllToLua.bat
|
||||
cd ..\..
|
||||
|
||||
|
||||
|
||||
|
||||
:: Compile using VC2008 Express. Do a full rebuild.
|
||||
echo Setting up VS environment...
|
||||
call "%VS90COMNTOOLS%\vsvars32.bat"
|
||||
echo Compiling MCServer...
|
||||
title MCS Nightbuild
|
||||
start "vc" /b /wait /low /min %vc% /r MCServer.sln "Release|Win32"
|
||||
if errorlevel 1 goto haderror
|
||||
|
||||
|
||||
|
||||
|
||||
:: Generate the .example.ini files by running the server without any ini files:
|
||||
cd MCServer
|
||||
del groups.ini
|
||||
del settings.ini
|
||||
del webadmin.ini
|
||||
echo stop | MCServer
|
||||
cd ..
|
||||
|
||||
|
||||
|
||||
:: Copy all the example ini files into the Install folder for zipping:
|
||||
copy MCServer\groups.ini Install\groups.example.ini
|
||||
copy MCServer\settings.ini Install\settings.example.ini
|
||||
copy MCServer\webadmin.ini Install\webadmin.example.ini
|
||||
|
||||
|
||||
|
||||
|
||||
:: Use 7-zip to compress the resulting files into a single file:
|
||||
set FILESUFFIX=%MYYEAR%_%MYMONTH%_%MYDAY%_%MYTIME%_%COMMITID%
|
||||
echo FILESUFFIX=%FILESUFFIX%
|
||||
copy MCServer\MCServer.exe Install\MCServer.exe
|
||||
cd Install
|
||||
%zip% a -mx9 -y MCServer_Win_%FILESUFFIX%.7z -scsWIN -i@Zip2008.list -xr!*.git*
|
||||
if errorlevel 1 goto haderror
|
||||
cd ..
|
||||
|
||||
:: Also pack PDBs into a separate archive:
|
||||
%zip% a -mx9 -y Install\PDBs_%FILESUFFIX%.7z -scsWIN @Install\Zip2008_PDBs.list
|
||||
if errorlevel 1 goto haderror
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
:: upload to the FTP:
|
||||
:upload
|
||||
ncftpput -p %ftppass% -u %ftpuser% -T temp_ %ftpsite% / Install\MCServer_Win_%FILESUFFIX%.7z
|
||||
if errorlevel 1 goto haderror
|
||||
ncftpput -p %ftppass% -u %ftpuser% -T temp_ %ftpsite% /PDBs Install\PDBs_%FILESUFFIX%.7z
|
||||
if errorlevel 1 goto haderror
|
||||
echo Upload finished.
|
||||
|
||||
|
||||
|
||||
|
||||
:: Create the tagfile so that we know that this CommitID has been built already
|
||||
mkdir %TAGFOLDER%
|
||||
touch %TAGFILE%
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
:: Add the symbols to a global symbol cache
|
||||
:: We want per-month symbol caches, so that the old ones can be easily deleted
|
||||
set SYMBOLS=Symbols\%MYYEAR%_%MYMONTH%\
|
||||
echo Storing symbols in %SYMBOLS%
|
||||
|
||||
symstore add /f MCServer\MCServer.* /s %SYMBOLS% /t MCServer
|
||||
if errorlevel 1 goto haderror
|
||||
|
||||
|
||||
|
||||
goto end
|
||||
|
||||
|
||||
|
||||
|
||||
:haderror
|
||||
echo an error was encountered, check command output above
|
||||
pause
|
||||
goto finished
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
:end
|
||||
if "a%1" == "a" pause
|
||||
|
||||
|
||||
|
||||
:finished
|
@ -8,11 +8,19 @@
|
||||
|
||||
|
||||
|
||||
static const int DELTA_STEP = 120; // The normal per-notch wheel delta
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
BiomeView::BiomeView(QWidget * parent) :
|
||||
super(parent),
|
||||
m_X(0),
|
||||
m_Z(0),
|
||||
m_Zoom(1)
|
||||
m_Zoom(1),
|
||||
m_IsMouseDragging(false),
|
||||
m_MouseWheelDelta(0)
|
||||
{
|
||||
// Create the image used for undefined chunks:
|
||||
int offset = 0;
|
||||
@ -33,6 +41,9 @@ BiomeView::BiomeView(QWidget * parent) :
|
||||
|
||||
// Add a chunk-update callback mechanism:
|
||||
connect(&m_Cache, SIGNAL(chunkAvailable(int, int)), this, SLOT(chunkAvailable(int, int)));
|
||||
|
||||
// Allow keyboard interaction:
|
||||
setFocusPolicy(Qt::StrongFocus);
|
||||
}
|
||||
|
||||
|
||||
@ -120,6 +131,21 @@ void BiomeView::chunkAvailable(int a_ChunkX, int a_ChunkZ)
|
||||
|
||||
|
||||
|
||||
void BiomeView::reload()
|
||||
{
|
||||
if (!hasData())
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_Cache.reload();
|
||||
|
||||
redraw();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void BiomeView::drawChunk(int a_ChunkX, int a_ChunkZ)
|
||||
{
|
||||
if (!hasData())
|
||||
@ -236,9 +262,164 @@ void BiomeView::paintEvent(QPaintEvent * a_Event)
|
||||
|
||||
|
||||
|
||||
void BiomeView::queueChunkRender(ChunkPtr a_Chunk)
|
||||
void BiomeView::mousePressEvent(QMouseEvent * a_Event)
|
||||
{
|
||||
|
||||
m_LastX = a_Event->x();
|
||||
m_LastY = a_Event->y();
|
||||
m_IsMouseDragging = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void BiomeView::mouseMoveEvent(QMouseEvent * a_Event)
|
||||
{
|
||||
if (m_IsMouseDragging)
|
||||
{
|
||||
// The user is dragging the mouse, move the view around:
|
||||
m_X += (m_LastX - a_Event->x()) / m_Zoom;
|
||||
m_Z += (m_LastY - a_Event->y()) / m_Zoom;
|
||||
m_LastX = a_Event->x();
|
||||
m_LastY = a_Event->y();
|
||||
redraw();
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Update the status bar info for the biome currently pointed at
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void BiomeView::mouseReleaseEvent(QMouseEvent *)
|
||||
{
|
||||
m_IsMouseDragging = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void BiomeView::wheelEvent(QWheelEvent * a_Event)
|
||||
{
|
||||
m_MouseWheelDelta += a_Event->delta();
|
||||
while (m_MouseWheelDelta >= DELTA_STEP)
|
||||
{
|
||||
increaseZoom();
|
||||
m_MouseWheelDelta -= DELTA_STEP;
|
||||
}
|
||||
while (m_MouseWheelDelta <= -DELTA_STEP)
|
||||
{
|
||||
decreaseZoom();
|
||||
m_MouseWheelDelta += DELTA_STEP;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void BiomeView::keyPressEvent(QKeyEvent * a_Event)
|
||||
{
|
||||
switch (a_Event->key())
|
||||
{
|
||||
case Qt::Key_Up:
|
||||
case Qt::Key_W:
|
||||
{
|
||||
m_Z -= 10.0 / m_Zoom;
|
||||
redraw();
|
||||
break;
|
||||
}
|
||||
|
||||
case Qt::Key_Down:
|
||||
case Qt::Key_S:
|
||||
{
|
||||
m_Z += 10.0 / m_Zoom;
|
||||
redraw();
|
||||
break;
|
||||
}
|
||||
|
||||
case Qt::Key_Left:
|
||||
case Qt::Key_A:
|
||||
{
|
||||
m_X -= 10.0 / m_Zoom;
|
||||
redraw();
|
||||
break;
|
||||
}
|
||||
|
||||
case Qt::Key_Right:
|
||||
case Qt::Key_D:
|
||||
{
|
||||
m_X += 10.0 / m_Zoom;
|
||||
redraw();
|
||||
break;
|
||||
}
|
||||
|
||||
case Qt::Key_PageUp:
|
||||
case Qt::Key_Q:
|
||||
{
|
||||
increaseZoom();
|
||||
break;
|
||||
}
|
||||
|
||||
case Qt::Key_PageDown:
|
||||
case Qt::Key_E:
|
||||
{
|
||||
decreaseZoom();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void BiomeView::decreaseZoom()
|
||||
{
|
||||
if (m_Zoom > 1.001)
|
||||
{
|
||||
m_Zoom--;
|
||||
if (m_Zoom < 1.0)
|
||||
{
|
||||
// Just crossed the 100%, fixate the 100% threshold:
|
||||
m_Zoom = 1.0;
|
||||
}
|
||||
}
|
||||
else if (m_Zoom > 0.01)
|
||||
{
|
||||
m_Zoom = m_Zoom / 2;
|
||||
}
|
||||
redraw();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void BiomeView::increaseZoom()
|
||||
{
|
||||
if (m_Zoom > 0.99)
|
||||
{
|
||||
if (m_Zoom > 20.0)
|
||||
{
|
||||
// Zoom too large
|
||||
return;
|
||||
}
|
||||
m_Zoom++;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Zoom = m_Zoom * 2;
|
||||
if (m_Zoom > 1.0)
|
||||
{
|
||||
// Just crossed the 100%, fixate the 100% threshold:
|
||||
m_Zoom = 1.0;
|
||||
}
|
||||
}
|
||||
redraw();
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
#include <memory>
|
||||
#include "ChunkCache.h"
|
||||
#include "ChunkSource.h"
|
||||
|
||||
@ -33,12 +34,28 @@ public slots:
|
||||
/** A specified chunk has become available, redraw it. */
|
||||
void chunkAvailable(int a_ChunkX, int a_ChunkZ);
|
||||
|
||||
/** Reloads the current chunk source and redraws the entire workspace. */
|
||||
void reload();
|
||||
|
||||
protected:
|
||||
double m_X, m_Z;
|
||||
int m_Zoom;
|
||||
double m_Zoom;
|
||||
|
||||
/** Cache for the loaded chunk data. */
|
||||
ChunkCache m_Cache;
|
||||
|
||||
/** The entire view's contents in an offscreen image. */
|
||||
QImage m_Image;
|
||||
|
||||
/** Coords of the mouse for the previous position, used while dragging. */
|
||||
int m_LastX, m_LastY;
|
||||
|
||||
/** Set to true when the user has a mouse button depressed, and is dragging the view. */
|
||||
bool m_IsMouseDragging;
|
||||
|
||||
/** Accumulator for the mouse wheel's delta. When the accumulator hits a threshold, the view zooms. */
|
||||
int m_MouseWheelDelta;
|
||||
|
||||
/** Data used for rendering a chunk that hasn't been loaded yet */
|
||||
uchar m_EmptyChunkImage[16 * 16 * 4];
|
||||
|
||||
@ -55,8 +72,26 @@ protected:
|
||||
/** Paints the entire widget */
|
||||
virtual void paintEvent(QPaintEvent *) override;
|
||||
|
||||
/** Queues the chunk for rendering. */
|
||||
void queueChunkRender(ChunkPtr a_Chunk);
|
||||
/** Called when the user presses any mouse button. */
|
||||
virtual void mousePressEvent(QMouseEvent * a_Event);
|
||||
|
||||
/** Called when the user moves the mouse. */
|
||||
virtual void mouseMoveEvent(QMouseEvent * a_Event);
|
||||
|
||||
/** Called when the user releases a previously held mouse button. */
|
||||
virtual void mouseReleaseEvent(QMouseEvent * a_Event) override;
|
||||
|
||||
/** Called when the user rotates the mouse wheel. */
|
||||
virtual void wheelEvent(QWheelEvent * a_Event) override;
|
||||
|
||||
/** Called when the user presses a key. */
|
||||
virtual void keyPressEvent(QKeyEvent * a_Event) override;
|
||||
|
||||
/** Decreases the zoom level and queues a redraw. */
|
||||
void decreaseZoom();
|
||||
|
||||
/** Increases the zoom level and queues a redraw. */
|
||||
void increaseZoom();
|
||||
};
|
||||
|
||||
|
||||
|
@ -76,6 +76,22 @@ void ChunkCache::setChunkSource(std::shared_ptr<ChunkSource> a_ChunkSource)
|
||||
|
||||
|
||||
|
||||
void ChunkCache::reload()
|
||||
{
|
||||
assert(m_ChunkSource.get() != nullptr);
|
||||
|
||||
// Reload the chunk source:
|
||||
m_ChunkSource->reload();
|
||||
|
||||
// Clear the cache:
|
||||
QMutexLocker lock(&m_Mtx);
|
||||
m_Cache.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void ChunkCache::gotChunk(int a_ChunkX, int a_ChunkZ)
|
||||
{
|
||||
emit chunkAvailable(a_ChunkX, a_ChunkZ);
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <QObject>
|
||||
#include <QCache>
|
||||
#include <QMutex>
|
||||
#include <memory>
|
||||
|
||||
|
||||
|
||||
@ -36,7 +37,10 @@ public:
|
||||
void setChunkSource(std::shared_ptr<ChunkSource> a_ChunkSource);
|
||||
|
||||
/** Returns true iff the chunk source has been initialized. */
|
||||
bool hasData(void) const { return (m_ChunkSource.get() != nullptr); }
|
||||
bool hasData() const { return (m_ChunkSource.get() != nullptr); }
|
||||
|
||||
/** Reloads the current chunk source. */
|
||||
void reload();
|
||||
|
||||
signals:
|
||||
void chunkAvailable(int a_ChunkX, int a_ChunkZ);
|
||||
|
@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QRunnable>
|
||||
#include <memory>
|
||||
|
||||
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include "Globals.h"
|
||||
#include "ChunkSource.h"
|
||||
#include <QThread>
|
||||
#include "Generating/BioGen.h"
|
||||
#include "inifile/iniFile.h"
|
||||
|
||||
|
||||
|
||||
@ -101,9 +103,9 @@ public:
|
||||
for (size_t i = 0; i < ARRAYCOUNT(biomeColors); i++)
|
||||
{
|
||||
uchar * color = &biomeToColor[4 * biomeColors[i].m_Biome];
|
||||
color[0] = biomeColors[i].m_Color[0];
|
||||
color[0] = biomeColors[i].m_Color[2];
|
||||
color[1] = biomeColors[i].m_Color[1];
|
||||
color[2] = biomeColors[i].m_Color[2];
|
||||
color[2] = biomeColors[i].m_Color[0];
|
||||
color[3] = 0xff;
|
||||
}
|
||||
}
|
||||
@ -118,8 +120,8 @@ static void biomesToImage(cChunkDef::BiomeMap & a_Biomes, Chunk::Image & a_Image
|
||||
{
|
||||
// Make sure the two arrays are of the same size, compile-time.
|
||||
// Note that a_Image is actually 4 items per pixel, so the array is 4 times bigger:
|
||||
static const char Check1[4 * ARRAYCOUNT(a_Biomes) - ARRAYCOUNT(a_Image) + 1];
|
||||
static const char Check2[ARRAYCOUNT(a_Image) - 4 * ARRAYCOUNT(a_Biomes) + 1];
|
||||
static const char Check1[4 * ARRAYCOUNT(a_Biomes) - ARRAYCOUNT(a_Image) + 1] = {};
|
||||
static const char Check2[ARRAYCOUNT(a_Image) - 4 * ARRAYCOUNT(a_Biomes) + 1] = {};
|
||||
|
||||
// Convert the biomes into color:
|
||||
for (size_t i = 0; i < ARRAYCOUNT(a_Biomes); i++)
|
||||
@ -138,9 +140,11 @@ static void biomesToImage(cChunkDef::BiomeMap & a_Biomes, Chunk::Image & a_Image
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// BioGenSource:
|
||||
|
||||
BioGenSource::BioGenSource(cBiomeGen * a_BiomeGen) :
|
||||
m_BiomeGen(a_BiomeGen)
|
||||
BioGenSource::BioGenSource(QString a_WorldIniPath) :
|
||||
m_WorldIniPath(a_WorldIniPath),
|
||||
m_Mtx(QMutex::Recursive)
|
||||
{
|
||||
reload();
|
||||
}
|
||||
|
||||
|
||||
@ -149,11 +153,11 @@ BioGenSource::BioGenSource(cBiomeGen * a_BiomeGen) :
|
||||
|
||||
void BioGenSource::getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChunk)
|
||||
{
|
||||
// TODO: To make use of multicore machines, we need multiple copies of the biomegen
|
||||
// Right now we have only one, so we can let only one thread use it (hence the mutex)
|
||||
QMutexLocker lock(&m_Mtx);
|
||||
cChunkDef::BiomeMap biomes;
|
||||
m_BiomeGen->GenBiomes(a_ChunkX, a_ChunkZ, biomes);
|
||||
{
|
||||
QMutexLocker lock(&m_Mtx);
|
||||
m_BiomeGen->GenBiomes(a_ChunkX, a_ChunkZ, biomes);
|
||||
}
|
||||
Chunk::Image img;
|
||||
biomesToImage(biomes, img);
|
||||
a_DestChunk->setImage(img);
|
||||
@ -162,3 +166,19 @@ void BioGenSource::getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChu
|
||||
|
||||
|
||||
|
||||
|
||||
void BioGenSource::reload()
|
||||
{
|
||||
cIniFile ini;
|
||||
ini.ReadFile(m_WorldIniPath.toStdString());
|
||||
int seed = ini.GetValueSetI("Seed", "Seed", 0);
|
||||
bool unused = false;
|
||||
QMutexLocker lock(&m_Mtx);
|
||||
m_BiomeGen.reset(cBiomeGen::CreateBiomeGen(ini, seed, unused));
|
||||
lock.unlock();
|
||||
ini.WriteFile(m_WorldIniPath.toStdString());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
#pragma once
|
||||
#include <QString>
|
||||
#include <QMutex>
|
||||
#include "Chunk.h"
|
||||
|
||||
|
||||
@ -7,6 +9,8 @@
|
||||
|
||||
// fwd:
|
||||
class cBiomeGen;
|
||||
typedef std::shared_ptr<cBiomeGen> cBiomeGenPtr;
|
||||
class cIniFile;
|
||||
|
||||
|
||||
|
||||
@ -21,6 +25,9 @@ public:
|
||||
/** Fills the a_DestChunk with the biomes for the specified coords.
|
||||
It is expected to be thread-safe and re-entrant. Usually QThread::idealThreadCount() threads are used. */
|
||||
virtual void getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChunk) = 0;
|
||||
|
||||
/** Forces a fresh reload of the source. Useful mainly for the generator, whose underlying definition file may have been changed. */
|
||||
virtual void reload() = 0;
|
||||
};
|
||||
|
||||
|
||||
@ -32,14 +39,21 @@ class BioGenSource :
|
||||
public ChunkSource
|
||||
{
|
||||
public:
|
||||
/** Constructs a new BioGenSource based on the biome generator given.
|
||||
Takes ownership of a_BiomeGen */
|
||||
BioGenSource(cBiomeGen * a_BiomeGen);
|
||||
/** Constructs a new BioGenSource based on the biome generator that is defined in the specified world.ini file. */
|
||||
BioGenSource(QString a_WorldIniPath);
|
||||
|
||||
// ChunkSource overrides:
|
||||
virtual void getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChunk) override;
|
||||
virtual void reload(void) override;
|
||||
|
||||
protected:
|
||||
std::shared_ptr<cBiomeGen> m_BiomeGen;
|
||||
/** Path to the world.ini file from which the m_WorldIni is regenerated on reload requests. */
|
||||
QString m_WorldIniPath;
|
||||
|
||||
/** The generator used for generating biomes. */
|
||||
std::unique_ptr<cBiomeGen> m_BiomeGen;
|
||||
|
||||
/** Guards m_BiomeGen against multithreaded access. */
|
||||
QMutex m_Mtx;
|
||||
};
|
||||
|
||||
@ -52,7 +66,9 @@ class AnvilSource :
|
||||
public:
|
||||
// TODO
|
||||
|
||||
// ChunkSource overrides:
|
||||
virtual void getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChunk) override;
|
||||
virtual void reload() override {}
|
||||
};
|
||||
|
||||
|
||||
|
@ -16,11 +16,11 @@
|
||||
MainWindow::MainWindow(QWidget * parent) :
|
||||
QMainWindow(parent)
|
||||
{
|
||||
createActions();
|
||||
createMenus();
|
||||
|
||||
m_BiomeView = new BiomeView(this);
|
||||
setCentralWidget(m_BiomeView);
|
||||
|
||||
createActions();
|
||||
createMenus();
|
||||
}
|
||||
|
||||
|
||||
@ -39,19 +39,7 @@ MainWindow::~MainWindow()
|
||||
void MainWindow::generate()
|
||||
{
|
||||
QString worldIni = QFileDialog::getOpenFileName(this, tr("Open world.ini"), QString(), tr("world.ini (world.ini)"));
|
||||
cIniFile ini;
|
||||
if (!ini.ReadFile(worldIni.toStdString()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
int seed = ini.GetValueSetI("Seed", "Seed", 0);
|
||||
bool unused = false;
|
||||
cBiomeGen * biomeGen = cBiomeGen::CreateBiomeGen(ini, seed, unused);
|
||||
if (biomeGen == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_BiomeView->setChunkSource(std::shared_ptr<BioGenSource>(new BioGenSource(biomeGen)));
|
||||
m_BiomeView->setChunkSource(std::shared_ptr<BioGenSource>(new BioGenSource(worldIni)));
|
||||
m_BiomeView->redraw();
|
||||
}
|
||||
|
||||
@ -80,6 +68,11 @@ void MainWindow::createActions()
|
||||
m_actOpen->setStatusTip(tr("Open an existing world and display its biomes"));
|
||||
connect(m_actOpen, SIGNAL(triggered()), this, SLOT(open()));
|
||||
|
||||
m_actReload = new QAction(tr("&Reload"), this);
|
||||
m_actReload->setShortcut(tr("F5"));
|
||||
m_actReload->setStatusTip(tr("Open an existing world and display its biomes"));
|
||||
connect(m_actReload, SIGNAL(triggered()), m_BiomeView, SLOT(reload()));
|
||||
|
||||
m_actExit = new QAction(tr("E&xit"), this);
|
||||
m_actExit->setShortcut(tr("Alt+X"));
|
||||
m_actExit->setStatusTip(tr("Exit %1").arg(QApplication::instance()->applicationName()));
|
||||
@ -96,6 +89,8 @@ void MainWindow::createMenus()
|
||||
mFile->addAction(m_actGen);
|
||||
mFile->addAction(m_actOpen);
|
||||
mFile->addSeparator();
|
||||
mFile->addAction(m_actReload);
|
||||
mFile->addSeparator();
|
||||
mFile->addAction(m_actExit);
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@ protected:
|
||||
// Actions:
|
||||
QAction * m_actGen;
|
||||
QAction * m_actOpen;
|
||||
QAction * m_actReload;
|
||||
QAction * m_actExit;
|
||||
|
||||
|
||||
|
@ -55,8 +55,6 @@ INCLUDEPATH += $$_PRO_FILE_PWD_ \
|
||||
$$_PRO_FILE_PWD_/../../lib
|
||||
|
||||
|
||||
CONFIG += STATIC
|
||||
|
||||
|
||||
CONFIG += C++11
|
||||
|
||||
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 203c2fb68bbf871eaf4ca98756a113d74d620dea
|
||||
Subproject commit 55edadd56d0d6f506954ad00c3b9a5d425814a2f
|
@ -427,7 +427,7 @@ void cBlockHandler::DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterfac
|
||||
if (a_CanDrop)
|
||||
{
|
||||
if ((a_Digger != NULL) && (a_Digger->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0))
|
||||
{
|
||||
{
|
||||
switch (m_BlockType)
|
||||
{
|
||||
case E_BLOCK_CAKE:
|
||||
|
@ -312,8 +312,16 @@ void cClientHandle::Authenticate(const AString & a_Name, const AString & a_UUID,
|
||||
ASSERT(m_Player == NULL);
|
||||
|
||||
m_Username = a_Name;
|
||||
m_UUID = a_UUID;
|
||||
m_Properties = a_Properties;
|
||||
|
||||
// Only assign UUID and properties if not already pre-assigned (BungeeCord sends those in the Handshake packet):
|
||||
if (m_UUID.empty())
|
||||
{
|
||||
m_UUID = a_UUID;
|
||||
}
|
||||
if (m_Properties.empty())
|
||||
{
|
||||
m_Properties = a_Properties;
|
||||
}
|
||||
|
||||
// Send login success (if the protocol supports it):
|
||||
m_Protocol->SendLoginSuccess();
|
||||
|
@ -64,15 +64,27 @@ public:
|
||||
|
||||
const AString & GetIPString(void) const { return m_IPString; } // tolua_export
|
||||
|
||||
/** Sets the IP string that the client is using. Overrides the IP string that was read from the socket.
|
||||
Used mainly by BungeeCord compatibility code. */
|
||||
void SetIPString(const AString & a_IPString) { m_IPString = a_IPString; }
|
||||
|
||||
cPlayer * GetPlayer(void) { return m_Player; } // tolua_export
|
||||
|
||||
/** Returns the player's UUID, as used by the protocol, in the short form (no dashes) */
|
||||
const AString & GetUUID(void) const { return m_UUID; } // tolua_export
|
||||
|
||||
void SetUUID(const AString & a_UUID) { m_UUID = a_UUID; }
|
||||
/** Sets the player's UUID, as used by the protocol. Short UUID form (no dashes) is expected.
|
||||
Used mainly by BungeeCord compatibility code - when authenticating is done on the BungeeCord server
|
||||
and the results are passed to MCS running in offline mode. */
|
||||
void SetUUID(const AString & a_UUID) { ASSERT(a_UUID.size() == 32); m_UUID = a_UUID; }
|
||||
|
||||
const Json::Value & GetProperties(void) const { return m_Properties; }
|
||||
|
||||
/** Sets the player's properties, such as skin image and signature.
|
||||
Used mainly by BungeeCord compatibility code - property querying is done on the BungeeCord server
|
||||
and the results are passed to MCS running in offline mode. */
|
||||
void SetProperties(const Json::Value & a_Properties) { m_Properties = a_Properties; }
|
||||
|
||||
/** Generates an UUID based on the username stored for this client, and stores it in the m_UUID member.
|
||||
This is used for the offline (non-auth) mode, when there's no UUID source.
|
||||
Each username generates a unique and constant UUID, so that when the player reconnects with the same name, their UUID is the same.
|
||||
|
@ -115,12 +115,14 @@ enum eGameMode
|
||||
eGameMode_Survival = 0,
|
||||
eGameMode_Creative = 1,
|
||||
eGameMode_Adventure = 2,
|
||||
eGameMode_Spectator = 3,
|
||||
|
||||
// Easier-to-use synonyms:
|
||||
gmNotSet = eGameMode_NotSet,
|
||||
gmSurvival = eGameMode_Survival,
|
||||
gmCreative = eGameMode_Creative,
|
||||
gmAdventure = eGameMode_Adventure,
|
||||
gmSpectator = eGameMode_Spectator,
|
||||
|
||||
// These two are used to check GameMode for validity when converting from integers.
|
||||
gmMax, // Gets automatically assigned
|
||||
|
@ -451,6 +451,11 @@ void cPlayer::CancelChargingBow(void)
|
||||
|
||||
void cPlayer::SetTouchGround(bool a_bTouchGround)
|
||||
{
|
||||
if (IsGameModeSpectator()) // You can fly through the ground in Spectator
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_bTouchGround = a_bTouchGround;
|
||||
|
||||
if (!m_bTouchGround)
|
||||
@ -585,7 +590,7 @@ bool cPlayer::Feed(int a_Food, double a_Saturation)
|
||||
|
||||
void cPlayer::AddFoodExhaustion(double a_Exhaustion)
|
||||
{
|
||||
if (!IsGameModeCreative())
|
||||
if (!(IsGameModeCreative() || IsGameModeSpectator()))
|
||||
{
|
||||
m_FoodExhaustionLevel = std::min(m_FoodExhaustionLevel + a_Exhaustion, 40.0);
|
||||
}
|
||||
@ -823,9 +828,9 @@ bool cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
{
|
||||
if ((a_TDI.DamageType != dtInVoid) && (a_TDI.DamageType != dtPlugin))
|
||||
{
|
||||
if (IsGameModeCreative())
|
||||
if (IsGameModeCreative() || IsGameModeSpectator())
|
||||
{
|
||||
// No damage / health in creative mode if not void or plugin damage
|
||||
// No damage / health in creative or spectator mode if not void or plugin damage
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1043,6 +1048,14 @@ bool cPlayer::IsGameModeAdventure(void) const
|
||||
|
||||
|
||||
|
||||
bool cPlayer::IsGameModeSpectator(void) const
|
||||
{
|
||||
return (m_GameMode == gmSpectator) || // Either the player is explicitly in Spectator
|
||||
((m_GameMode == gmNotSet) && m_World->IsGameModeSpectator()); // or they inherit from the world and the world is Adventure
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void cPlayer::SetTeam(cTeam * a_Team)
|
||||
{
|
||||
@ -1158,7 +1171,7 @@ void cPlayer::SetGameMode(eGameMode a_GameMode)
|
||||
m_GameMode = a_GameMode;
|
||||
m_ClientHandle->SendGameMode(a_GameMode);
|
||||
|
||||
if (!IsGameModeCreative())
|
||||
if (!(IsGameModeCreative() || IsGameModeSpectator()))
|
||||
{
|
||||
SetFlying(false);
|
||||
SetCanFly(false);
|
||||
@ -1342,6 +1355,7 @@ void cPlayer::MoveTo( const Vector3d & a_NewPos)
|
||||
|
||||
void cPlayer::SetVisible(bool a_bVisible)
|
||||
{
|
||||
// Need to Check if the player or other players are in gamemode spectator, but will break compatibility
|
||||
if (a_bVisible && !m_bVisible) // Make visible
|
||||
{
|
||||
m_bVisible = true;
|
||||
@ -1502,6 +1516,11 @@ void cPlayer::TossPickup(const cItem & a_Item)
|
||||
|
||||
void cPlayer::TossItems(const cItems & a_Items)
|
||||
{
|
||||
if (IsGameModeSpectator()) // Players can't toss items in spectator
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_Stats.AddValue(statItemsDropped, (StatValue)a_Items.Size());
|
||||
|
||||
double vX = 0, vY = 0, vZ = 0;
|
||||
@ -1788,7 +1807,7 @@ bool cPlayer::SaveToDisk()
|
||||
|
||||
void cPlayer::UseEquippedItem(int a_Amount)
|
||||
{
|
||||
if (IsGameModeCreative()) // No damage in creative
|
||||
if (IsGameModeCreative() || IsGameModeSpectator()) // No damage in creative or spectator
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -171,6 +171,9 @@ public:
|
||||
/** Returns true if the player is in Adventure mode, either explicitly, or by inheriting from current world */
|
||||
bool IsGameModeAdventure(void) const;
|
||||
|
||||
/** Returns true if the player is in Spectator mode, either explicitly, or by inheriting from current world */
|
||||
bool IsGameModeSpectator(void) const;
|
||||
|
||||
AString GetIP(void) const { return m_IP; } // tolua_export
|
||||
|
||||
/** Returns the associated team, NULL if none */
|
||||
|
@ -12,72 +12,6 @@
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cBiomeGen:
|
||||
|
||||
cBiomeGen * cBiomeGen::CreateBiomeGen(cIniFile & a_IniFile, int a_Seed, bool & a_CacheOffByDefault)
|
||||
{
|
||||
AString BiomeGenName = a_IniFile.GetValueSet("Generator", "BiomeGen", "");
|
||||
if (BiomeGenName.empty())
|
||||
{
|
||||
LOGWARN("[Generator] BiomeGen value not set in world.ini, using \"MultiStepMap\".");
|
||||
BiomeGenName = "MultiStepMap";
|
||||
}
|
||||
|
||||
cBiomeGen * res = NULL;
|
||||
a_CacheOffByDefault = false;
|
||||
if (NoCaseCompare(BiomeGenName, "constant") == 0)
|
||||
{
|
||||
res = new cBioGenConstant;
|
||||
a_CacheOffByDefault = true; // we're generating faster than a cache would retrieve data :)
|
||||
}
|
||||
else if (NoCaseCompare(BiomeGenName, "checkerboard") == 0)
|
||||
{
|
||||
res = new cBioGenCheckerboard;
|
||||
a_CacheOffByDefault = true; // we're (probably) generating faster than a cache would retrieve data
|
||||
}
|
||||
else if (NoCaseCompare(BiomeGenName, "voronoi") == 0)
|
||||
{
|
||||
res = new cBioGenVoronoi(a_Seed);
|
||||
}
|
||||
else if (NoCaseCompare(BiomeGenName, "distortedvoronoi") == 0)
|
||||
{
|
||||
res = new cBioGenDistortedVoronoi(a_Seed);
|
||||
}
|
||||
else if (NoCaseCompare(BiomeGenName, "twolevel") == 0)
|
||||
{
|
||||
res = new cBioGenTwoLevel(a_Seed);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (NoCaseCompare(BiomeGenName, "multistepmap") != 0)
|
||||
{
|
||||
LOGWARNING("Unknown BiomeGen \"%s\", using \"MultiStepMap\" instead.", BiomeGenName.c_str());
|
||||
}
|
||||
res = new cBioGenMultiStepMap(a_Seed);
|
||||
|
||||
/*
|
||||
// Performance-testing:
|
||||
LOGINFO("Measuring performance of cBioGenMultiStepMap...");
|
||||
clock_t BeginTick = clock();
|
||||
for (int x = 0; x < 5000; x++)
|
||||
{
|
||||
cChunkDef::BiomeMap Biomes;
|
||||
res->GenBiomes(x * 5, x * 5, Biomes);
|
||||
}
|
||||
clock_t Duration = clock() - BeginTick;
|
||||
LOGINFO("cBioGenMultiStepMap for 5000 chunks took %d ticks (%.02f sec)", Duration, (double)Duration / CLOCKS_PER_SEC);
|
||||
//*/
|
||||
}
|
||||
res->InitializeBiomeGen(a_IniFile);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cBioGenConstant:
|
||||
|
||||
@ -402,8 +336,13 @@ void cBioGenVoronoi::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap &
|
||||
void cBioGenVoronoi::InitializeBiomeGen(cIniFile & a_IniFile)
|
||||
{
|
||||
super::InitializeBiomeGen(a_IniFile);
|
||||
m_Voronoi.SetCellSize(a_IniFile.GetValueSetI("Generator", "VoronoiCellSize", 64));
|
||||
InitializeBiomes (a_IniFile.GetValueSet ("Generator", "VoronoiBiomes", ""));
|
||||
int CellSize = a_IniFile.GetValueSetI("Generator", "VoronoiCellSize", 128);
|
||||
int JitterSize = a_IniFile.GetValueSetI("Generator", "VoronoiJitterSize", CellSize);
|
||||
int OddRowOffset = a_IniFile.GetValueSetI("Generator", "VoronoiOddRowOffset", 0);
|
||||
m_Voronoi.SetCellSize(CellSize);
|
||||
m_Voronoi.SetJitterSize(JitterSize);
|
||||
m_Voronoi.SetOddRowOffset(OddRowOffset);
|
||||
InitializeBiomes(a_IniFile.GetValueSet ("Generator", "VoronoiBiomes", ""));
|
||||
}
|
||||
|
||||
|
||||
@ -846,9 +785,10 @@ void cBioGenTwoLevel::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap
|
||||
{
|
||||
for (int x = 0; x < cChunkDef::Width; x++)
|
||||
{
|
||||
int MinDist1, MinDist2;
|
||||
int BiomeGroup = m_VoronoiLarge.GetValueAt(DistortX[x][z], DistortZ[x][z], MinDist1, MinDist2) / 7;
|
||||
int BiomeIdx = m_VoronoiSmall.GetValueAt(DistortX[x][z], DistortZ[x][z], MinDist1, MinDist2) / 11;
|
||||
int SeedX, SeedZ, MinDist2;
|
||||
int BiomeGroup = m_VoronoiLarge.GetValueAt(DistortX[x][z], DistortZ[x][z], SeedX, SeedZ, MinDist2) / 7;
|
||||
int BiomeIdx = m_VoronoiSmall.GetValueAt(DistortX[x][z], DistortZ[x][z], SeedX, SeedZ, MinDist2) / 11;
|
||||
int MinDist1 = (DistortX[x][z] - SeedX) * (DistortX[x][z] - SeedX) + (DistortZ[x][z] - SeedZ) * (DistortZ[x][z] - SeedZ);
|
||||
cChunkDef::SetBiome(a_BiomeMap, x, z, SelectBiome(BiomeGroup, BiomeIdx, (MinDist1 < MinDist2 / 4) ? 0 : 1));
|
||||
}
|
||||
}
|
||||
@ -987,3 +927,69 @@ void cBioGenTwoLevel::InitializeBiomeGen(cIniFile & a_IniFile)
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cBiomeGen:
|
||||
|
||||
cBiomeGen * cBiomeGen::CreateBiomeGen(cIniFile & a_IniFile, int a_Seed, bool & a_CacheOffByDefault)
|
||||
{
|
||||
AString BiomeGenName = a_IniFile.GetValueSet("Generator", "BiomeGen", "");
|
||||
if (BiomeGenName.empty())
|
||||
{
|
||||
LOGWARN("[Generator] BiomeGen value not set in world.ini, using \"MultiStepMap\".");
|
||||
BiomeGenName = "MultiStepMap";
|
||||
}
|
||||
|
||||
cBiomeGen * res = NULL;
|
||||
a_CacheOffByDefault = false;
|
||||
if (NoCaseCompare(BiomeGenName, "constant") == 0)
|
||||
{
|
||||
res = new cBioGenConstant;
|
||||
a_CacheOffByDefault = true; // we're generating faster than a cache would retrieve data :)
|
||||
}
|
||||
else if (NoCaseCompare(BiomeGenName, "checkerboard") == 0)
|
||||
{
|
||||
res = new cBioGenCheckerboard;
|
||||
a_CacheOffByDefault = true; // we're (probably) generating faster than a cache would retrieve data
|
||||
}
|
||||
else if (NoCaseCompare(BiomeGenName, "voronoi") == 0)
|
||||
{
|
||||
res = new cBioGenVoronoi(a_Seed);
|
||||
}
|
||||
else if (NoCaseCompare(BiomeGenName, "distortedvoronoi") == 0)
|
||||
{
|
||||
res = new cBioGenDistortedVoronoi(a_Seed);
|
||||
}
|
||||
else if (NoCaseCompare(BiomeGenName, "twolevel") == 0)
|
||||
{
|
||||
res = new cBioGenTwoLevel(a_Seed);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (NoCaseCompare(BiomeGenName, "multistepmap") != 0)
|
||||
{
|
||||
LOGWARNING("Unknown BiomeGen \"%s\", using \"MultiStepMap\" instead.", BiomeGenName.c_str());
|
||||
}
|
||||
res = new cBioGenMultiStepMap(a_Seed);
|
||||
|
||||
/*
|
||||
// Performance-testing:
|
||||
LOGINFO("Measuring performance of cBioGenMultiStepMap...");
|
||||
clock_t BeginTick = clock();
|
||||
for (int x = 0; x < 5000; x++)
|
||||
{
|
||||
cChunkDef::BiomeMap Biomes;
|
||||
res->GenBiomes(x * 5, x * 5, Biomes);
|
||||
}
|
||||
clock_t Duration = clock() - BeginTick;
|
||||
LOGINFO("cBioGenMultiStepMap for 5000 chunks took %d ticks (%.02f sec)", Duration, (double)Duration / CLOCKS_PER_SEC);
|
||||
//*/
|
||||
}
|
||||
res->InitializeBiomeGen(a_IniFile);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -102,6 +102,19 @@ cProtocol172::cProtocol172(cClientHandle * a_Client, const AString & a_ServerAdd
|
||||
m_IsEncrypted(false),
|
||||
m_LastSentDimension(dimNotSet)
|
||||
{
|
||||
// BungeeCord handling:
|
||||
// If BC is setup with ip_forward == true, it sends additional data in the login packet's ServerAddress field:
|
||||
// hostname\00ip-address\00uuid\00profile-properties-as-json
|
||||
AStringVector Params;
|
||||
if (cRoot::Get()->GetServer()->ShouldAllowBungeeCord() && SplitZeroTerminatedStrings(a_ServerAddress, Params) && (Params.size() == 4))
|
||||
{
|
||||
LOGD("Player at %s connected via BungeeCord", Params[1].c_str());
|
||||
m_ServerAddress = Params[0];
|
||||
m_Client->SetIPString(Params[1]);
|
||||
m_Client->SetUUID(cMojangAPI::MakeUUIDShort(Params[2]));
|
||||
m_Client->SetProperties(Params[3]);
|
||||
}
|
||||
|
||||
// Create the comm log file, if so requested:
|
||||
if (g_ShouldLogCommIn || g_ShouldLogCommOut)
|
||||
{
|
||||
|
@ -28,7 +28,7 @@
|
||||
cProtocolRecognizer::cProtocolRecognizer(cClientHandle * a_Client) :
|
||||
super(a_Client),
|
||||
m_Protocol(NULL),
|
||||
m_Buffer(512)
|
||||
m_Buffer(8192) // We need a larger buffer to support BungeeCord - it sends one huge packet at the start
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -113,8 +113,8 @@ void cRoot::Start(void)
|
||||
LOG("--- Started Log ---\n");
|
||||
|
||||
#ifdef BUILD_ID
|
||||
LOG("MCServer " BUILD_SERIES_NAME " build id: " BUILD_ID );
|
||||
LOG("from commit id: " BUILD_COMMIT_ID " built at: " BUILD_DATETIME );
|
||||
LOG("MCServer " BUILD_SERIES_NAME " build id: " BUILD_ID);
|
||||
LOG("from commit id: " BUILD_COMMIT_ID " built at: " BUILD_DATETIME);
|
||||
#endif
|
||||
|
||||
cDeadlockDetect dd;
|
||||
|
@ -259,6 +259,13 @@ bool cServer::InitServer(cIniFile & a_SettingsIni)
|
||||
m_ServerID = sid.str();
|
||||
m_ServerID.resize(16, '0');
|
||||
}
|
||||
|
||||
// Check if both BungeeCord and online mode are on, if so, warn the admin:
|
||||
m_ShouldAllowBungeeCord = a_SettingsIni.GetValueSetB("Authentication", "AllowBungeeCord", false);
|
||||
if (m_ShouldAllowBungeeCord && m_ShouldAuthenticate)
|
||||
{
|
||||
LOGWARNING("WARNING: BungeeCord is allowed and server set to online mode. This is unsafe and will not work properly. Disable either authentication or BungeeCord in settings.ini.");
|
||||
}
|
||||
|
||||
m_ShouldLoadOfflinePlayerData = a_SettingsIni.GetValueSetB("PlayerData", "LoadOfflinePlayerData", false);
|
||||
m_ShouldLoadNamedPlayerData = a_SettingsIni.GetValueSetB("PlayerData", "LoadNamedPlayerData", true);
|
||||
|
@ -131,6 +131,11 @@ public: // tolua_export
|
||||
Loaded from the settings.ini [PlayerData].LoadNamedPlayerData setting. */
|
||||
bool ShouldLoadNamedPlayerData(void) const { return m_ShouldLoadNamedPlayerData; }
|
||||
|
||||
/** Returns true if BungeeCord logins (that specify the player's UUID) are allowed.
|
||||
Read from settings, admins should set this to true only when they chain to BungeeCord,
|
||||
it makes the server vulnerable to identity theft through direct connections. */
|
||||
bool ShouldAllowBungeeCord(void) const { return m_ShouldAllowBungeeCord; }
|
||||
|
||||
private:
|
||||
|
||||
friend class cRoot; // so cRoot can create and destroy cServer
|
||||
@ -230,6 +235,9 @@ private:
|
||||
This allows a seamless transition from name-based to UUID-based player storage.
|
||||
Loaded from the settings.ini [PlayerData].LoadNamedPlayerData setting. */
|
||||
bool m_ShouldLoadNamedPlayerData;
|
||||
|
||||
/** True if BungeeCord handshake packets (with player UUID) should be accepted. */
|
||||
bool m_ShouldAllowBungeeCord;
|
||||
|
||||
|
||||
cServer(void);
|
||||
|
@ -869,3 +869,31 @@ void SetBEInt(char * a_Mem, Int32 a_Value)
|
||||
|
||||
|
||||
|
||||
|
||||
bool SplitZeroTerminatedStrings(const AString & a_Strings, AStringVector & a_Output)
|
||||
{
|
||||
a_Output.clear();
|
||||
size_t size = a_Strings.size();
|
||||
size_t start = 0;
|
||||
bool res = false;
|
||||
for (size_t i = 0; i < size; i++)
|
||||
{
|
||||
if (a_Strings[i] == 0)
|
||||
{
|
||||
a_Output.push_back(a_Strings.substr(start, i - start));
|
||||
start = i + 1;
|
||||
res = true;
|
||||
}
|
||||
}
|
||||
if (start < size)
|
||||
{
|
||||
a_Output.push_back(a_Strings.substr(start, size - start));
|
||||
res = true;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -99,6 +99,11 @@ extern int GetBEInt(const char * a_Mem);
|
||||
/// Writes four bytes to the specified memory location so that they interpret as BigEndian int
|
||||
extern void SetBEInt(char * a_Mem, Int32 a_Value);
|
||||
|
||||
/** Splits a string that has embedded \0 characters, on those characters.
|
||||
a_Output is first cleared and then each separate string is pushed back into a_Output.
|
||||
Returns true if there are at least two strings in a_Output (there was at least one \0 separator). */
|
||||
extern bool SplitZeroTerminatedStrings(const AString & a_Strings, AStringVector & a_Output);
|
||||
|
||||
/// Parses any integer type. Checks bounds and returns errors out of band.
|
||||
template <class T>
|
||||
bool StringToInteger(const AString & a_str, T & a_Num)
|
||||
|
@ -10,11 +10,13 @@
|
||||
|
||||
|
||||
|
||||
cVoronoiMap::cVoronoiMap(int a_Seed, int a_CellSize) :
|
||||
cVoronoiMap::cVoronoiMap(int a_Seed, int a_CellSize, int a_JitterSize) :
|
||||
m_Noise1(a_Seed + 1),
|
||||
m_Noise2(a_Seed + 2),
|
||||
m_Noise3(a_Seed + 3),
|
||||
m_CellSize(a_CellSize),
|
||||
m_CellSize(std::max(a_CellSize, 2)),
|
||||
m_JitterSize(Clamp(a_JitterSize, 1, a_CellSize)),
|
||||
m_OddRowOffset(0),
|
||||
m_CurrentCellX(9999999), // Cell coords that are definitely out of the range for normal generator, so that the first query will overwrite them
|
||||
m_CurrentCellZ(9999999)
|
||||
{
|
||||
@ -26,7 +28,29 @@ cVoronoiMap::cVoronoiMap(int a_Seed, int a_CellSize) :
|
||||
|
||||
void cVoronoiMap::SetCellSize(int a_CellSize)
|
||||
{
|
||||
a_CellSize = std::max(a_CellSize, 2); // Cell size must be at least 2
|
||||
m_CellSize = a_CellSize;
|
||||
|
||||
// For compatibility with previous version, which didn't have the jitter, we set jitter here as well.
|
||||
m_JitterSize = a_CellSize;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cVoronoiMap::SetJitterSize(int a_JitterSize)
|
||||
{
|
||||
m_JitterSize = Clamp(a_JitterSize, 1, m_CellSize);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cVoronoiMap::SetOddRowOffset(int a_OddRowOffset)
|
||||
{
|
||||
m_OddRowOffset = Clamp(a_OddRowOffset, -m_CellSize, m_CellSize);
|
||||
}
|
||||
|
||||
|
||||
@ -35,8 +59,8 @@ void cVoronoiMap::SetCellSize(int a_CellSize)
|
||||
|
||||
int cVoronoiMap::GetValueAt(int a_X, int a_Y)
|
||||
{
|
||||
int MinDist1, MinDist2;
|
||||
return GetValueAt(a_X, a_Y, MinDist1, MinDist2);
|
||||
int SeedX, SeedY, MinDist2;
|
||||
return GetValueAt(a_X, a_Y, SeedX, SeedY, MinDist2);
|
||||
}
|
||||
|
||||
|
||||
@ -45,41 +69,47 @@ int cVoronoiMap::GetValueAt(int a_X, int a_Y)
|
||||
|
||||
int cVoronoiMap::GetValueAt(int a_X, int a_Y, int & a_MinDist)
|
||||
{
|
||||
int MinDist2;
|
||||
return GetValueAt(a_X, a_Y, a_MinDist, MinDist2);
|
||||
int SeedX, SeedY, MinDist2;
|
||||
int res = GetValueAt(a_X, a_Y, SeedX, SeedY, MinDist2);
|
||||
a_MinDist = (a_X - SeedX) * (a_X - SeedX) + (a_Y - SeedY) * (a_Y - SeedY);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cVoronoiMap::GetValueAt(int a_X, int a_Y, int & a_MinDist1, int & a_MinDist2)
|
||||
int cVoronoiMap::GetValueAt(
|
||||
int a_X, int a_Y, // Coords to query
|
||||
int & a_NearestSeedX, int & a_NearestSeedY, // Coords of the closest cell
|
||||
int & a_MinDist2 // Distance to the second closest cell
|
||||
)
|
||||
{
|
||||
// Note that due to historical reasons, the algorithm uses XZ coords, while the input uses XY coords.
|
||||
// This is because the algorithm was first implemented directly in the biome generators which use MC coords.
|
||||
|
||||
int CellX = a_X / m_CellSize;
|
||||
int CellZ = a_Y / m_CellSize;
|
||||
int CellY = a_Y / m_CellSize;
|
||||
|
||||
UpdateCell(CellX, CellZ);
|
||||
UpdateCell(CellX, CellY);
|
||||
|
||||
// Get 5x5 neighboring cell seeds, compare distance to each. Return the value in the minumim-distance cell
|
||||
int NearestSeedX = 0, NearestSeedY = 0;
|
||||
int MinDist = m_CellSize * m_CellSize * 16; // There has to be a cell closer than this
|
||||
int MinDist2 = MinDist;
|
||||
int res = 0; // Will be overriden
|
||||
for (int x = 0; x < 5; x++)
|
||||
{
|
||||
for (int z = 0; z < 5; z++)
|
||||
for (int y = 0; y < 5; y++)
|
||||
{
|
||||
int SeedX = m_SeedX[x][z];
|
||||
int SeedZ = m_SeedZ[x][z];
|
||||
int SeedX = m_SeedX[x][y];
|
||||
int SeedY = m_SeedZ[x][y];
|
||||
|
||||
int Dist = (SeedX - a_X) * (SeedX - a_X) + (SeedZ - a_Y) * (SeedZ - a_Y);
|
||||
int Dist = (SeedX - a_X) * (SeedX - a_X) + (SeedY - a_Y) * (SeedY - a_Y);
|
||||
if (Dist < MinDist)
|
||||
{
|
||||
NearestSeedX = SeedX;
|
||||
NearestSeedY = SeedY;
|
||||
MinDist2 = MinDist;
|
||||
MinDist = Dist;
|
||||
res = m_Noise3.IntNoise2DInt(x + CellX - 2, z + CellZ - 2);
|
||||
res = m_Noise3.IntNoise2DInt(x + CellX - 2, y + CellY - 2);
|
||||
}
|
||||
else if (Dist < MinDist2)
|
||||
{
|
||||
@ -88,7 +118,8 @@ int cVoronoiMap::GetValueAt(int a_X, int a_Y, int & a_MinDist1, int & a_MinDist2
|
||||
} // for z
|
||||
} // for x
|
||||
|
||||
a_MinDist1 = MinDist;
|
||||
a_NearestSeedX = NearestSeedX;
|
||||
a_NearestSeedY = NearestSeedY;
|
||||
a_MinDist2 = MinDist2;
|
||||
return res;
|
||||
}
|
||||
@ -97,6 +128,58 @@ int cVoronoiMap::GetValueAt(int a_X, int a_Y, int & a_MinDist1, int & a_MinDist2
|
||||
|
||||
|
||||
|
||||
void cVoronoiMap::FindNearestSeeds(
|
||||
int a_X, int a_Y,
|
||||
int & a_NearestSeedX, int & a_NearestSeedY,
|
||||
int & a_SecondNearestSeedX, int & a_SecondNearestSeedY
|
||||
)
|
||||
{
|
||||
int CellX = a_X / m_CellSize;
|
||||
int CellY = a_Y / m_CellSize;
|
||||
|
||||
UpdateCell(CellX, CellY);
|
||||
|
||||
// Get 5x5 neighboring cell seeds, compare distance to each. Return the value in the minumim-distance cell
|
||||
int NearestSeedX = 0, NearestSeedY = 0;
|
||||
int SecondNearestSeedX = 0, SecondNearestSeedY = 0;
|
||||
int MinDist = m_CellSize * m_CellSize * 16; // There has to be a cell closer than this
|
||||
int MinDist2 = MinDist;
|
||||
for (int x = 0; x < 5; x++)
|
||||
{
|
||||
for (int y = 0; y < 5; y++)
|
||||
{
|
||||
int SeedX = m_SeedX[x][y];
|
||||
int SeedY = m_SeedZ[x][y];
|
||||
|
||||
int Dist = (SeedX - a_X) * (SeedX - a_X) + (SeedY - a_Y) * (SeedY - a_Y);
|
||||
if (Dist < MinDist)
|
||||
{
|
||||
SecondNearestSeedX = NearestSeedX;
|
||||
SecondNearestSeedY = NearestSeedY;
|
||||
MinDist2 = MinDist;
|
||||
NearestSeedX = SeedX;
|
||||
NearestSeedY = SeedY;
|
||||
MinDist = Dist;
|
||||
}
|
||||
else if (Dist < MinDist2)
|
||||
{
|
||||
SecondNearestSeedX = SeedX;
|
||||
SecondNearestSeedY = SeedY;
|
||||
MinDist2 = Dist;
|
||||
}
|
||||
} // for z
|
||||
} // for x
|
||||
|
||||
a_NearestSeedX = NearestSeedX;
|
||||
a_NearestSeedY = NearestSeedY;
|
||||
a_SecondNearestSeedX = SecondNearestSeedX;
|
||||
a_SecondNearestSeedY = SecondNearestSeedY;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cVoronoiMap::UpdateCell(int a_CellX, int a_CellZ)
|
||||
{
|
||||
// If the specified cell is currently cached, bail out:
|
||||
@ -111,12 +194,13 @@ void cVoronoiMap::UpdateCell(int a_CellX, int a_CellZ)
|
||||
for (int x = 0; x < 5; x++)
|
||||
{
|
||||
int BaseX = (NoiseBaseX + x) * m_CellSize;
|
||||
int OddRowOffset = ((NoiseBaseX + x) & 0x01) * m_OddRowOffset;
|
||||
for (int z = 0; z < 5; z++)
|
||||
{
|
||||
int OffsetX = (m_Noise1.IntNoise2DInt(NoiseBaseX + x, NoiseBaseZ + z) / 8) % m_CellSize;
|
||||
int OffsetZ = (m_Noise2.IntNoise2DInt(NoiseBaseX + x, NoiseBaseZ + z) / 8) % m_CellSize;
|
||||
int OffsetX = (m_Noise1.IntNoise2DInt(NoiseBaseX + x, NoiseBaseZ + z) / 8) % m_JitterSize;
|
||||
int OffsetZ = (m_Noise2.IntNoise2DInt(NoiseBaseX + x, NoiseBaseZ + z) / 8) % m_JitterSize;
|
||||
m_SeedX[x][z] = BaseX + OffsetX;
|
||||
m_SeedZ[x][z] = (NoiseBaseZ + z) * m_CellSize + OffsetZ;
|
||||
m_SeedZ[x][z] = (NoiseBaseZ + z) * m_CellSize + OddRowOffset + OffsetZ;
|
||||
} // for z
|
||||
} // for x
|
||||
m_CurrentCellX = a_CellX;
|
||||
|
@ -18,19 +18,40 @@
|
||||
class cVoronoiMap
|
||||
{
|
||||
public:
|
||||
cVoronoiMap(int a_Seed, int a_CellSize = 128);
|
||||
cVoronoiMap(int a_Seed, int a_CellSize = 128, int a_JitterSize = 128);
|
||||
|
||||
/// Sets the cell size used for generating the Voronoi seeds
|
||||
/** Sets both the cell size and jitter size used for generating the Voronoi seeds. */
|
||||
void SetCellSize(int a_CellSize);
|
||||
|
||||
/** Sets the jitter size. Clamps it to current cell size. */
|
||||
void SetJitterSize(int a_JitterSize);
|
||||
|
||||
/** Sets the offset that is added to each odd row of cells.
|
||||
This offset makes the voronoi cells align to a non-grid.
|
||||
Clamps the value to [-m_CellSize, +m_CellSize]. */
|
||||
void SetOddRowOffset(int a_OddRowOffset);
|
||||
|
||||
/// Returns the value in the cell into which the specified point lies
|
||||
/** Returns the value in the cell into which the specified point lies. */
|
||||
int GetValueAt(int a_X, int a_Y);
|
||||
|
||||
/// Returns the value in the cell into which the specified point lies, and the distance to the nearest Voronoi seed
|
||||
/** Returns the value in the cell into which the specified point lies,
|
||||
and the distance to the nearest Voronoi seed. */
|
||||
int GetValueAt(int a_X, int a_Y, int & a_MinDistance);
|
||||
|
||||
/// Returns the value in the cell into which the specified point lies, and the distances to the 2 nearest Voronoi seeds. Uses a cache
|
||||
int GetValueAt(int a_X, int a_Y, int & a_MinDistance1, int & a_MinDistance2);
|
||||
/** Returns the value in the cell into which the specified point lies,
|
||||
and the distances to the 2 nearest Voronoi seeds. Uses a cache. */
|
||||
int GetValueAt(
|
||||
int a_X, int a_Y, // Coords to query
|
||||
int & a_NearestSeedX, int & a_NearestSeedY, // Coords of the closest cell's seed
|
||||
int & a_MinDist2 // Distance to the second closest cell's seed
|
||||
);
|
||||
|
||||
/** Finds the nearest and second nearest seeds, returns their coords. */
|
||||
void FindNearestSeeds(
|
||||
int a_X, int a_Y,
|
||||
int & a_NearestSeedX, int & a_NearestSeedY,
|
||||
int & a_SecondNearestSeedX, int & a_SecondNearestSeedY
|
||||
);
|
||||
|
||||
protected:
|
||||
/// The noise used for generating Voronoi seeds
|
||||
@ -38,8 +59,17 @@ protected:
|
||||
cNoise m_Noise2;
|
||||
cNoise m_Noise3;
|
||||
|
||||
/// Size of the Voronoi cells (avg X/Y distance between the seeds)
|
||||
/** Size of the Voronoi cells (avg X/Y distance between the seeds). Expected to be at least 2. */
|
||||
int m_CellSize;
|
||||
|
||||
/** The amount that the cell seeds may be offset from the grid.
|
||||
Expected to be at least 1 and less than m_CellSize. */
|
||||
int m_JitterSize;
|
||||
|
||||
/** The constant amount that the cell seeds of every odd row will be offset from the grid.
|
||||
This allows us to have non-rectangular grids.
|
||||
Expected to be between -m_CellSize and +m_CellSize. */
|
||||
int m_OddRowOffset;
|
||||
|
||||
/** The X coordinate of the currently cached cell neighborhood */
|
||||
int m_CurrentCellX;
|
||||
|
@ -188,6 +188,9 @@ public:
|
||||
/** Returns true if the world is in Adventure mode */
|
||||
bool IsGameModeAdventure(void) const { return (m_GameMode == gmAdventure); }
|
||||
|
||||
/** Returns true if the world is in Spectator mode */
|
||||
bool IsGameModeSpectator(void) const { return (m_GameMode == gmSpectator); }
|
||||
|
||||
bool IsPVPEnabled(void) const { return m_bEnabledPVP; }
|
||||
bool IsDeepSnowEnabled(void) const { return m_IsDeepSnowEnabled; }
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user