summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTycho <work.tycho+git@gmail.com>2014-09-17 19:47:33 +0200
committerTycho <work.tycho+git@gmail.com>2014-09-17 19:47:33 +0200
commit045d54e0e28a9338b171c93c5bbc9ccba4c79ef1 (patch)
tree58e083f5b1f97baf6de712485d3629bdcac275a8
parentAdded first test to show the object can be created (diff)
parentBungeeCord compatibility: don't overwrite UUID / properties. (diff)
downloadcuberite-045d54e0e28a9338b171c93c5bbc9ccba4c79ef1.tar
cuberite-045d54e0e28a9338b171c93c5bbc9ccba4c79ef1.tar.gz
cuberite-045d54e0e28a9338b171c93c5bbc9ccba4c79ef1.tar.bz2
cuberite-045d54e0e28a9338b171c93c5bbc9ccba4c79ef1.tar.lz
cuberite-045d54e0e28a9338b171c93c5bbc9ccba4c79ef1.tar.xz
cuberite-045d54e0e28a9338b171c93c5bbc9ccba4c79ef1.tar.zst
cuberite-045d54e0e28a9338b171c93c5bbc9ccba4c79ef1.zip
Diffstat (limited to '')
-rw-r--r--CONTRIBUTORS1
-rw-r--r--MCServer/Plugins/APIDump/APIDesc.lua10
-rw-r--r--Nightbuild2008.cmd209
-rw-r--r--README.md6
-rw-r--r--Tools/.gitignore1
-rw-r--r--Tools/BiomeVisualiser/.gitignore4
-rw-r--r--Tools/BiomeVisualiser/BiomeCache.cpp338
-rw-r--r--Tools/BiomeVisualiser/BiomeCache.h96
-rw-r--r--Tools/BiomeVisualiser/BiomeColors.cpp114
-rw-r--r--Tools/BiomeVisualiser/BiomeColors.h15
-rw-r--r--Tools/BiomeVisualiser/BiomeRenderer.cpp119
-rw-r--r--Tools/BiomeVisualiser/BiomeRenderer.h55
-rw-r--r--Tools/BiomeVisualiser/BiomeSource.h37
-rw-r--r--Tools/BiomeVisualiser/BiomeViewWnd.cpp247
-rw-r--r--Tools/BiomeVisualiser/BiomeViewWnd.h69
-rw-r--r--Tools/BiomeVisualiser/BiomeVisualiser.cpp52
-rw-r--r--Tools/BiomeVisualiser/BiomeVisualiser.h31
-rw-r--r--Tools/BiomeVisualiser/BiomeVisualiser.sln23
-rw-r--r--Tools/BiomeVisualiser/BiomeVisualiser.vcproj527
-rw-r--r--Tools/BiomeVisualiser/GeneratorBiomeSource.h42
-rw-r--r--Tools/BiomeVisualiser/Pixmap.cpp120
-rw-r--r--Tools/BiomeVisualiser/Pixmap.h39
-rw-r--r--Tools/BiomeVisualiser/Timer.h40
-rw-r--r--Tools/BiomeVisualiser/WndProcThunk.h143
-rw-r--r--Tools/BiomeVisualiser/profile_run.cmd70
-rw-r--r--Tools/QtBiomeVisualiser/.gitignore2
-rw-r--r--Tools/QtBiomeVisualiser/BiomeView.cpp427
-rw-r--r--Tools/QtBiomeVisualiser/BiomeView.h99
-rw-r--r--Tools/QtBiomeVisualiser/Chunk.cpp36
-rw-r--r--Tools/QtBiomeVisualiser/Chunk.h40
-rw-r--r--Tools/QtBiomeVisualiser/ChunkCache.cpp126
-rw-r--r--Tools/QtBiomeVisualiser/ChunkCache.h71
-rw-r--r--Tools/QtBiomeVisualiser/ChunkLoader.cpp29
-rw-r--r--Tools/QtBiomeVisualiser/ChunkLoader.h43
-rw-r--r--Tools/QtBiomeVisualiser/ChunkSource.cpp184
-rw-r--r--Tools/QtBiomeVisualiser/ChunkSource.h75
-rw-r--r--Tools/QtBiomeVisualiser/Globals.h386
-rw-r--r--Tools/QtBiomeVisualiser/MainWindow.cpp99
-rw-r--r--Tools/QtBiomeVisualiser/MainWindow.h47
-rw-r--r--Tools/QtBiomeVisualiser/QtBiomeVisualiser.pro59
-rw-r--r--Tools/QtBiomeVisualiser/main.cpp20
-rw-r--r--src/BlockInfo.cpp26
-rw-r--r--src/Blocks/BlockBed.cpp2
-rw-r--r--src/Blocks/BlockBigFlower.h6
-rw-r--r--src/Blocks/BlockDoor.cpp2
-rw-r--r--src/Blocks/BlockFarmland.h99
-rw-r--r--src/Blocks/BlockFenceGate.h6
-rw-r--r--src/Blocks/BlockFire.h4
-rw-r--r--src/Blocks/BlockGravel.h13
-rw-r--r--src/Blocks/BlockHandler.cpp70
-rw-r--r--src/Blocks/BlockHandler.h2
-rw-r--r--src/Blocks/BlockMobHead.h12
-rw-r--r--src/Blocks/BlockMobSpawner.h40
-rw-r--r--src/Blocks/BlockOre.h3
-rw-r--r--src/Blocks/BlockPiston.cpp2
-rw-r--r--src/Blocks/ChunkInterface.cpp4
-rw-r--r--src/Blocks/ChunkInterface.h2
-rw-r--r--src/Blocks/WorldInterface.h3
-rw-r--r--src/Chunk.cpp2
-rw-r--r--src/ChunkMap.cpp6
-rw-r--r--src/ChunkMap.h4
-rw-r--r--src/ClientHandle.cpp36
-rw-r--r--src/ClientHandle.h14
-rw-r--r--src/Entities/Entity.cpp41
-rw-r--r--src/Entities/Entity.h6
-rw-r--r--src/Entities/EntityEffect.cpp86
-rw-r--r--src/Entities/EntityEffect.h8
-rw-r--r--src/Entities/Player.cpp9
-rw-r--r--src/Items/ItemFood.h2
-rw-r--r--src/Items/ItemGoldenApple.h1
-rw-r--r--src/Items/ItemHandler.cpp10
-rw-r--r--src/Items/ItemHoe.h8
-rw-r--r--src/Items/ItemMilk.h8
-rw-r--r--src/Items/ItemMushroomSoup.h53
-rw-r--r--src/Items/ItemPickaxe.h1
-rw-r--r--src/Items/ItemPotion.h8
-rw-r--r--src/Mobs/Monster.cpp6
-rw-r--r--src/Mobs/Monster.h5
-rw-r--r--src/OSSupport/File.cpp14
-rw-r--r--src/OSSupport/IsThread.h2
-rw-r--r--src/Protocol/Protocol17x.cpp19
-rw-r--r--src/Protocol/ProtocolRecognizer.cpp2
-rw-r--r--src/StringUtils.cpp28
-rw-r--r--src/StringUtils.h5
-rw-r--r--src/VoronoiMap.cpp35
-rw-r--r--src/VoronoiMap.h31
-rw-r--r--src/World.cpp2
-rw-r--r--src/World.h2
88 files changed, 2318 insertions, 2583 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 925e8f35b..2d911a11d 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -29,5 +29,6 @@ worktycho
xoft
Yeeeeezus (Donated AlchemistVillage prefabs)
Howaner
+Masy98
Please add yourself to this list if you contribute to MCServer.
diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua
index c23120600..2f791293d 100644
--- a/MCServer/Plugins/APIDump/APIDesc.lua
+++ b/MCServer/Plugins/APIDump/APIDesc.lua
@@ -1641,6 +1641,8 @@ a_Player:OpenWindow(Window);
MobTypeToString = { Params = "{{cMonster#MobType|MobType}}", Return = "string", Notes = "(STATIC) Returns the string representing the given mob type ({{cMonster#MobType|mtXXX}} constant), or empty string if unknown type." },
MoveToPosition = { Params = "Position", Return = "", Notes = "Moves mob to the specified position" },
StringToMobType = { Params = "string", Return = "{{cMonster#MobType|MobType}}", Notes = "(STATIC) Returns the mob type ({{cMonster#MobType|mtXXX}} constant) parsed from the string type (\"creeper\"), or mtInvalidType if unrecognized." },
+ GetRelativeWalkSpeed = { Params = "", Return = "number", Notes = "Returns the relative walk speed of this mob. Standard is 1.0" },
+ SetRelativeWalkSpeed = { Params = "number", Return = "", Notes = "Sets the relative walk speed of this mob. Standard is 1.0" },
},
Constants =
{
@@ -1885,13 +1887,13 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage);
},
BindCommand =
{
- { Params = "Command, Permission, Callback, HelpString", Return = "[bool]", Notes = "(STATIC) Binds an in-game command with the specified callback function, permission and help string. By common convention, providing an empty string for HelpString will hide the command from the /help display. Returns true if successful, logs to console and returns no value on error." },
- { Params = "Command, Permission, Callback, HelpString", Return = "[bool]", Notes = "Binds an in-game command with the specified callback function, permission and help string. By common convention, providing an empty string for HelpString will hide the command from the /help display. Returns true if successful, logs to console and returns no value on error." },
+ { Params = "Command, Permission, Callback, HelpString", Return = "[bool]", Notes = "(STATIC) Binds an in-game command with the specified callback function, permission and help string. By common convention, providing an empty string for HelpString will hide the command from the /help display. Returns true if successful, logs to console and returns no value on error. The callback uses the following signature: <pre class=\"prettyprint lang-lua\">function(Split, {{cPlayer|Player}})</pre> The Split parameter contains an array-table of the words that the player has sent, Player is the {{cPlayer}} object representing the player who sent the command. If the callback returns true, the command is assumed to have executed successfully; in all other cases the server sends a warning to the player that the command is unknown (this is so that subcommands can be implemented)." },
+ { Params = "Command, Permission, Callback, HelpString", Return = "[bool]", Notes = "Binds an in-game command with the specified callback function, permission and help string. By common convention, providing an empty string for HelpString will hide the command from the /help display. Returns true if successful, logs to console and returns no value on error. The callback uses the following signature: <pre class=\"prettyprint lang-lua\">function(Split, {{cPlayer|Player}})</pre> The Split parameter contains an array-table of the words that the player has sent, Player is the {{cPlayer}} object representing the player who sent the command. If the callback returns true, the command is assumed to have executed successfully; in all other cases the server sends a warning to the player that the command is unknown (this is so that subcommands can be implemented)." },
},
BindConsoleCommand =
{
- { Params = "Command, Callback, HelpString", Return = "[bool]", Notes = "(STATIC) Binds a console command with the specified callback function and help string. By common convention, providing an empty string for HelpString will hide the command from the \"help\" console command. Returns true if successful, logs to console and returns no value on error." },
- { Params = "Command, Callback, HelpString", Return = "[bool]", Notes = "Binds a console command with the specified callback function and help string. By common convention, providing an empty string for HelpString will hide the command from the \"help\" console command. Returns true if successful, logs to console and returns no value on error." },
+ { Params = "Command, Callback, HelpString", Return = "[bool]", Notes = "(STATIC) Binds a console command with the specified callback function and help string. By common convention, providing an empty string for HelpString will hide the command from the \"help\" console command. Returns true if successful, logs to console and returns no value on error. The callback uses the following signature: <pre class=\"prettyprint lang-lua\">function(Split)</pre> The Split parameter contains an array-table of the words that the admin has typed. If the callback returns true, the command is assumed to have executed successfully; in all other cases the server issues a warning to the console that the command is unknown (this is so that subcommands can be implemented)." },
+ { Params = "Command, Callback, HelpString", Return = "[bool]", Notes = "Binds a console command with the specified callback function and help string. By common convention, providing an empty string for HelpString will hide the command from the \"help\" console command. Returns true if successful, logs to console and returns no value on error. The callback uses the following signature: <pre class=\"prettyprint lang-lua\">function(Split)</pre> The Split parameter contains an array-table of the words that the admin has typed. If the callback returns true, the command is assumed to have executed successfully; in all other cases the server issues a warning to the console that the command is unknown (this is so that subcommands can be implemented)." },
},
CallPlugin = { Params = "PluginName, FunctionName, [FunctionArgs...]", Return = "[FunctionRets]", Notes = "(STATIC) Calls the specified function in the specified plugin, passing all the given arguments to it. If it succeeds, it returns all the values returned by that function. If it fails, returns no value at all. Note that only strings, numbers, bools, nils and classes can be used for parameters and return values; tables and functions cannot be copied across plugins." },
DisablePlugin = { Params = "PluginName", Return = "bool", Notes = "Disables a plugin specified by its name. Returns true if the plugin was disabled, false if it wasn't found or wasn't active." },
diff --git a/Nightbuild2008.cmd b/Nightbuild2008.cmd
deleted file mode 100644
index bbaea0fb7..000000000
--- a/Nightbuild2008.cmd
+++ /dev/null
@@ -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 \ No newline at end of file
diff --git a/README.md b/README.md
index 85ae459a0..27166413e 100644
--- a/README.md
+++ b/README.md
@@ -12,8 +12,8 @@ Installation
Normally, you will want to download a pre-compiled version of MCServer from one of the buildservers:
- * [Linux and Raspberry Pi](http://ci.bearbin.net) (Bearbin's CI Server)
- * [Windows](http://mc-server.xoft.cz) (xoft's nightly build service)
+ * [Windows and Linux](http://builds.mc-server.org)
+ * [Raspberry Pi](http://ci.bearbin.net)
You simply need to download and extract these files before you can use the server.
@@ -33,7 +33,7 @@ For other stuff, including plugins and discussion, check the [forums](http://for
Earn bitcoins for commits or donate to reward the MCServer developers: [![tip for next commit](http://tip4commit.com/projects/74.svg)](http://tip4commit.com/projects/74)
-Support Us on Gittip: [![Support via Gittip](http://img.shields.io/gittip/mcs_team.svg)](https://www.gittip.com/mcs_team)
+Support Us on Gratipay: [![Support via Gittip](http://img.shields.io/gittip/mcs_team.svg)](https://www.gittip.com/mcs_team)
Travis CI: [![Build Status](http://img.shields.io/travis/mc-server/MCServer.svg)](https://travis-ci.org/mc-server/MCServer)
diff --git a/Tools/.gitignore b/Tools/.gitignore
new file mode 100644
index 000000000..f240e723e
--- /dev/null
+++ b/Tools/.gitignore
@@ -0,0 +1 @@
+Debug/
diff --git a/Tools/BiomeVisualiser/.gitignore b/Tools/BiomeVisualiser/.gitignore
deleted file mode 100644
index cfbc9164c..000000000
--- a/Tools/BiomeVisualiser/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-Debug/
-logs/
-Release/
-Release profiled/
diff --git a/Tools/BiomeVisualiser/BiomeCache.cpp b/Tools/BiomeVisualiser/BiomeCache.cpp
deleted file mode 100644
index 7d9301d8f..000000000
--- a/Tools/BiomeVisualiser/BiomeCache.cpp
+++ /dev/null
@@ -1,338 +0,0 @@
-
-// BiomeCache.cpp
-
-// Implements the cBiomeCache class representing a biome source that caches data from the underlying biome source
-
-#include "Globals.h"
-#include "BiomeCache.h"
-#include "Timer.h"
-
-
-
-
-
-static int GetNumCores(void)
-{
- // Get number of cores by querying the system process affinity mask
- DWORD Affinity, ProcAffinity;
- GetProcessAffinityMask(GetCurrentProcess(), &ProcAffinity, &Affinity);
- int NumCores = 0;
- while (Affinity > 0)
- {
- if ((Affinity & 1) == 1)
- {
- NumCores++;
- }
- Affinity >>= 1;
- } // while (Affinity > 0)
- return NumCores;
-}
-
-
-
-
-
-cBiomeCache::cBiomeCache(void) :
- m_Source(NULL),
- m_BaseX(-100000),
- m_BaseZ(-100000),
- m_Available(NULL),
- m_IsTerminatingThreads(false)
-{
- int NumThreads = GetNumCores();
- NumThreads--; // One core should be left for the system to run on ;)
- for (int i = NumThreads; i > 0; i--)
- {
- cThread * Thread = new cThread(*this);
- m_Threads.push_back(Thread);
- Thread->Start();
- }
-}
-
-
-
-
-cBiomeCache::~cBiomeCache()
-{
- m_IsTerminatingThreads = true;
- for (cThreads::iterator itr = m_Threads.begin(), end = m_Threads.end(); itr != end; ++itr)
- {
- m_evtQueued.Set();
- }
- for (cThreads::iterator itr = m_Threads.begin(), end = m_Threads.end(); itr != end; ++itr)
- {
- delete *itr;
- }
- m_Threads.clear();
-
- SetSource(NULL);
-}
-
-
-
-
-
-cBiomeSource::eAvailability cBiomeCache::GetBiome(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_Biomes)
-{
- if (m_Source == NULL)
- {
- return baNever;
- }
-
- // Look up using the cache:
- int x = a_ChunkX - m_BaseX;
- int z = a_ChunkZ - m_BaseZ;
- if ((x < 0) || (x >= m_Width) || (z < 0) || (z >= m_Height))
- {
- // Outside the cached region
- return baNever;
- }
-
- cCSLock Lock(m_CS);
- cItem * Item = m_Available[x + m_Width * z];
- if (Item == NULL)
- {
- // Item hasn't been processed yet
- return baLater;
- }
- if (Item->m_IsValid)
- {
- memcpy(a_Biomes, Item->m_Biomes, sizeof(a_Biomes));
- return baNow;
- }
-
- // Item has been processed, but the underlying source refused to give the data to us
- return baNever;
-}
-
-
-
-
-
-void cBiomeCache::HintViewArea(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ)
-{
- cTimer Timer("Cache: HintViewArea");
-
- if (
- (a_MinChunkX == m_BaseX) &&
- (a_MaxChunkX == m_BaseX + m_Width - 1) &&
- (a_MinChunkZ == m_BaseZ) &&
- (a_MaxChunkZ == m_BaseZ + m_Height - 1)
- )
- {
- // The same set of parameters, bail out
- return;
- }
-
- if (m_Source != NULL)
- {
- m_Source->HintViewArea(a_MinChunkX, a_MaxChunkX, a_MinChunkZ, a_MaxChunkZ);
- }
-
- int NewWidth = a_MaxChunkX - a_MinChunkX + 1;
- int NewHeight = a_MaxChunkZ - a_MinChunkZ + 1;
-
- // Make a new empty cache table:
- pItem * NewAvailable = new pItem[NewWidth * NewHeight];
- for (int i = NewWidth * NewHeight - 1; i >= 0; --i)
- {
- NewAvailable[i] = NULL;
- }
-
- // Move the common contents of the old table into the new table:
- cCSLock Lock(m_CS);
- for (int z = 0; z < NewHeight; z++)
- {
- int OldZ = z + a_MinChunkZ - m_BaseZ;
- if ((OldZ < 0) || (OldZ >= m_Height))
- {
- continue;
- }
- for (int x = 0; x < NewWidth; x++)
- {
- int OldX = x + a_MinChunkX - m_BaseX;
- if ((OldX < 0) || (OldX >= m_Width))
- {
- continue;
- }
- NewAvailable[x + NewWidth * z] = m_Available[OldX + m_Width * OldZ];
- m_Available[OldX + m_Width * OldZ] = NULL;
- } // for x
- } // for z
-
- // All items that aren't common go into the pool:
- for (int idx = 0, z = 0; z < m_Height; z++)
- {
- for (int x = 0; x < m_Width; ++x, ++idx)
- {
- if (m_Available[idx] != NULL)
- {
- m_Pool.push_back(m_Available[idx]);
- m_Available[idx] = NULL;
- }
- }
- }
-
- // Replace the cache table:
- delete m_Available;
- m_Available = NewAvailable;
- m_Width = NewWidth;
- m_Height = NewHeight;
- m_BaseX = a_MinChunkX;
- m_BaseZ = a_MinChunkZ;
-
- // Remove all items outside the coords:
- FilterOutItems(m_Queue, a_MinChunkX, a_MaxChunkX, a_MinChunkZ, a_MaxChunkZ);
-
- // Queue all items from inside the coords into m_Queue:
- for (int z = 0; z < NewHeight; z++)
- {
- for (int x = 0; x < NewWidth; x++)
- {
- if (m_Available[x + m_Width * z] != NULL)
- {
- // Already calculated, skip
- continue;
- }
-
- if (m_Pool.empty())
- {
- m_Pool.push_back(new cItem(x + a_MinChunkX, z + a_MinChunkZ));
- }
- ASSERT(!m_Pool.empty());
- m_Pool.back()->m_ChunkX = x + a_MinChunkX;
- m_Pool.back()->m_ChunkZ = z + a_MinChunkZ;
- m_Queue.push_back(m_Pool.back());
- m_Pool.pop_back();
- m_evtQueued.Set();
- } // for x
- } // for z
-}
-
-
-
-
-
-void cBiomeCache::SetSource(cBiomeSource * a_Source)
-{
- // TODO: Stop all threads, so that they don't use the source anymore!
-
- delete m_Source;
- m_Source = a_Source;
-
- // Invalidate cache contents:
- cCSLock Lock(m_CS);
- m_BaseX = -10000;
- m_BaseZ = -10000;
- m_Pool.splice(m_Pool.end(), m_Queue);
-}
-
-
-
-
-
-void cBiomeCache::FilterOutItems(cItems & a_Items, int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ)
-{
- for (cItems::iterator itr = a_Items.begin(); itr != a_Items.end();)
- {
- if (
- ((*itr)->m_ChunkX < a_MinChunkX) ||
- ((*itr)->m_ChunkX > a_MaxChunkX) ||
- ((*itr)->m_ChunkX < a_MinChunkX) ||
- ((*itr)->m_ChunkX > a_MaxChunkX)
- )
- {
- m_Pool.push_back(*itr);
- itr = a_Items.erase(itr);
- }
- else
- {
- ++itr;
- }
- }
-}
-
-
-
-
-
-void cBiomeCache::thrProcessQueueItem(void)
-{
- if (m_Source == NULL)
- {
- return;
- }
-
- cItem * Item = NULL;
- {
- cCSLock Lock(m_CS);
- if (m_Queue.empty())
- {
- cCSUnlock Unlock(Lock);
- m_evtQueued.Wait();
- }
- if (m_IsTerminatingThreads || m_Queue.empty())
- {
- // We've been woken up only to die / spurious wakeup
- return;
- }
- Item = m_Queue.back();
- m_Queue.pop_back();
- }
-
- // Process the item:
- Item->m_IsValid = (m_Source->GetBiome(Item->m_ChunkX, Item->m_ChunkZ, Item->m_Biomes) == baNow);
-
- // Store result:
- cCSLock Lock(m_CS);
- int x = Item->m_ChunkX - m_BaseX;
- int z = Item->m_ChunkZ - m_BaseZ;
- if ((x < 0) || (x >= m_Width) || (z < 0) || (z >= m_Height))
- {
- // The cache rectangle has changed under our fingers, drop this chunk
- return;
- }
- m_Available[x + m_Width * z] = Item;
-}
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// cBiomeCache::cItem:
-
-cBiomeCache::cItem::cItem(int a_ChunkX, int a_ChunkZ) :
- m_ChunkX(a_ChunkX),
- m_ChunkZ(a_ChunkZ)
-{
-}
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// cBiomeCache::cThread:
-
-cBiomeCache::cThread::cThread(cBiomeCache & a_Parent) :
- super("Biome cache thread"),
- m_Parent(a_Parent)
-{
-}
-
-
-
-
-
-void cBiomeCache::cThread::Execute(void)
-{
- while (!m_ShouldTerminate && !m_Parent.m_IsTerminatingThreads)
- {
- m_Parent.thrProcessQueueItem();
- }
-}
-
-
-
-
diff --git a/Tools/BiomeVisualiser/BiomeCache.h b/Tools/BiomeVisualiser/BiomeCache.h
deleted file mode 100644
index da4d6c761..000000000
--- a/Tools/BiomeVisualiser/BiomeCache.h
+++ /dev/null
@@ -1,96 +0,0 @@
-
-// BiomeCache.h
-
-// Declares the cBiomeCache class representing a biome source that caches data from the underlying biome source
-
-/*
-This cache works a bit differently than regular caches.
-It first receives the hint of area that it will need to provide.
-The Cache uses several threads to request biomes from the underlying source to fill that area.
-While the area is being filled, requests for biomes may already come, such requests are answered with baLater if no data yet.
-*/
-
-#pragma once
-
-
-
-
-
-#include "BiomeSource.h"
-#include "../src/OSSupport/IsThread.h"
-
-
-
-
-
-class cBiomeCache :
- public cBiomeSource
-{
-public:
- cBiomeCache(void);
- ~cBiomeCache();
-
- // cBiomeSource overrides:
- virtual eAvailability GetBiome(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_Biomes) override;
- virtual void HintViewArea(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ) override;
-
- void SetSource(cBiomeSource * a_Source); // Takes ownership of the source ptr
-
-protected:
- class cItem
- {
- public:
- cItem(int a_ChunkX, int a_ChunkZ);
-
- int m_ChunkX;
- int m_ChunkZ;
- bool m_IsValid;
- cChunkDef::BiomeMap m_Biomes;
- } ;
-
- typedef cItem * pItem;
- typedef std::list<pItem> cItems;
-
- class cThread :
- public cIsThread
- {
- typedef cIsThread super;
-
- public:
- cThread(cBiomeCache & a_Parent);
-
- // cIsThread overrides:
- virtual void Execute(void) override;
-
- protected:
- cBiomeCache & m_Parent;
- } ;
-
- typedef std::list<cThread *> cThreads;
-
- cBiomeSource * m_Source;
-
- cCriticalSection m_CS;
- int m_BaseX; ///< MinChunkX for the m_Available rectangle
- int m_BaseZ; ///< MinChunkZ for the m_Available rectangle
- int m_Width; ///< Width of the m_Available rectangle
- int m_Height; ///< Height of the m_Available rectangle
- pItem * m_Available; ///< Items that have already been processed (baNow or baNever), [x + m_Width * z]
- cItems m_Queue; ///< Items that are queued for processing (baLater)
- cItems m_Pool; ///< Items that are not needed anymore, can be reused for other coords
-
- cEvent m_evtQueued; // Triggerred when an item is added to m_Queue
-
- cThreads m_Threads; // Threads that update the cache.
- bool m_IsTerminatingThreads; // Set to true to indicate to all threads that they should exit
-
- /// Removes from a_Items all items that are outside of the given coords, moves those into m_Pool
- void FilterOutItems(cItems & a_Items, int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ);
-
- /// Processes one item from m_Queue into m_Available. Blocks if m_Queue is empty; respects m_IsTerminatingThreads
- void thrProcessQueueItem(void);
-} ;
-
-
-
-
diff --git a/Tools/BiomeVisualiser/BiomeColors.cpp b/Tools/BiomeVisualiser/BiomeColors.cpp
deleted file mode 100644
index 1fd0cb7a0..000000000
--- a/Tools/BiomeVisualiser/BiomeColors.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-
-// BiomeColors.cpp
-
-// Implements the g_BiomeColors[] array preparation based on a stored biome-to-color map
-
-#include "Globals.h"
-#include "BiomeColors.h"
-
-
-
-
-
-int g_BiomeColors[256];
-
-
-
-
-
-static struct
-{
- EMCSBiome Biome;
- int Color;
-} g_BiomeColorMap[] =
-{
- { biOcean, 0x000070 },
- { biPlains, 0x8db360 },
- { biDesert, 0xfa9418 },
- { biExtremeHills, 0x606060 },
- { biForest, 0x056621 },
- { biTaiga, 0x0b6659 },
- { biSwampland, 0x2fffda },
- { biRiver, 0x3030af },
- { biHell, 0x7f0000 },
- { biSky, 0x007fff },
- { biFrozenOcean, 0xa0a0df },
- { biFrozenRiver, 0xa0a0ff },
- { biIcePlains, 0xffffff },
- { biIceMountains, 0xa0a0a0 },
- { biMushroomIsland, 0xff00ff },
- { biMushroomShore, 0xa000ff },
- { biBeach, 0xfade55 },
- { biDesertHills, 0xd25f12 },
- { biForestHills, 0x22551c },
- { biTaigaHills, 0x163933 },
- { biExtremeHillsEdge, 0x7f8f7f },
- { biJungle, 0x537b09 },
- { biJungleHills, 0x2c4205 },
-
- { biJungleEdge, 0x628b17 },
- { biDeepOcean, 0x000030 },
- { biStoneBeach, 0xa2a284 },
- { biColdBeach, 0xfaf0c0 },
- { biBirchForest, 0x307444 },
- { biBirchForestHills, 0x1f5f32 },
- { biRoofedForest, 0x40511a },
- { biColdTaiga, 0x31554a },
- { biColdTaigaHills, 0x597d72 },
- { biMegaTaiga, 0x596651 },
- { biMegaTaigaHills, 0x596659 },
- { biExtremeHillsPlus, 0x507050 },
- { biSavanna, 0xbdb25f },
- { biSavannaPlateau, 0xa79d64 },
- { biMesa, 0xd94515 },
- { biMesaPlateauF, 0xb09765 },
- { biMesaPlateau, 0xca8c65 },
-
- // M variants:
- { biSunflowerPlains, 0xb5db88 },
- { biDesertM, 0xffbc40 },
- { biExtremeHillsM, 0x888888 },
- { biFlowerForest, 0x2d8e49 },
- { biTaigaM, 0x338e81 },
- { biSwamplandM, 0x07f9b2 },
- { biIcePlainsSpikes, 0xb4dcdc },
- { biJungleM, 0x7ba331 },
- { biJungleEdgeM, 0x628b17 },
- { biBirchForestM, 0x589c6c },
- { biBirchForestHillsM, 0x47875a },
- { biRoofedForestM, 0x687942 },
- { biColdTaigaM, 0x243f36 },
- { biMegaSpruceTaiga, 0x454f3e },
- { biMegaSpruceTaigaHills, 0x454f4e },
- { biExtremeHillsPlusM, 0x789878 },
- { biSavannaM, 0xe5da87 },
- { biSavannaPlateauM, 0xa79d74 },
- { biMesaBryce, 0xff6d3d },
- { biMesaPlateauFM, 0xd8bf8d },
- { biMesaPlateauM, 0xf2b48d },
-} ;
-
-
-
-
-
-static class cBiomeColorsInitializer
-{
-public:
- cBiomeColorsInitializer(void)
- {
- // Reset all colors to gray:
- for (size_t i = 0; i < ARRAYCOUNT(g_BiomeColors); i++)
- {
- g_BiomeColors[i] = 0x7f7f7f;
- }
- for (size_t i = 0; i < ARRAYCOUNT(g_BiomeColorMap); i++)
- {
- g_BiomeColors[g_BiomeColorMap[i].Biome] = g_BiomeColorMap[i].Color;
- }
- }
-} g_Initializer;
-
-
-
-
diff --git a/Tools/BiomeVisualiser/BiomeColors.h b/Tools/BiomeVisualiser/BiomeColors.h
deleted file mode 100644
index 0cb0f578c..000000000
--- a/Tools/BiomeVisualiser/BiomeColors.h
+++ /dev/null
@@ -1,15 +0,0 @@
-
-// BiomeColors.h
-
-// Declares the g_BiomeColors[] array used for biome color lookup
-
-
-
-
-
-extern int g_BiomeColors[256];
-
-
-
-
-
diff --git a/Tools/BiomeVisualiser/BiomeRenderer.cpp b/Tools/BiomeVisualiser/BiomeRenderer.cpp
deleted file mode 100644
index c0123c08a..000000000
--- a/Tools/BiomeVisualiser/BiomeRenderer.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-
-// BiomeRenderer.cpp
-
-// Implements the cBiomeRenderer class representing the rendering engine
-
-#include "Globals.h"
-#include "BiomeRenderer.h"
-#include "Pixmap.h"
-#include "Timer.h"
-#include "BiomeColors.h"
-
-
-
-
-
-cBiomeRenderer::cBiomeRenderer(void) :
- m_OriginX(160),
- m_OriginY(160),
- m_Zoom(1)
-{
-}
-
-
-
-
-void cBiomeRenderer::SetSource(cBiomeSource * a_Source)
-{
- m_Cache.SetSource(a_Source);
-}
-
-
-
-
-
-bool cBiomeRenderer::Render(cPixmap & a_Pixmap)
-{
- cTimer Timer("cBiomeRenderer::Render");
-
- int Wid = a_Pixmap.GetWidth();
- int Hei = a_Pixmap.GetHeight();
-
- // Hint the approximate view area to the biome source so that it can adjust its caches:
- int MinBlockX = ( - m_OriginX) * m_Zoom;
- int MaxBlockX = (Wid - m_OriginX) * m_Zoom;
- int MinBlockZ = ( - m_OriginY) * m_Zoom;
- int MaxBlockZ = (Hei - m_OriginY) * m_Zoom;
- m_Cache.HintViewArea(MinBlockX / 16 - 1, MaxBlockX / 16 + 1, MinBlockZ / 16 - 1, MaxBlockZ / 16 + 1);
-
- // Hold one current chunk of biome data:
- int CurChunkX = -10000;
- int CurChunkZ = -10000;
- cChunkDef::BiomeMap CurBiomes;
-
- bool res = false;
-
- for (int y = 0; y < Hei; y++)
- {
- int BlockZ = (y - m_OriginY) * m_Zoom;
- int ChunkZ = (BlockZ >= 0) ? (BlockZ / 16) : ((BlockZ + 1) / 16 - 1);
- int RelZ = BlockZ - ChunkZ * 16;
- for (int x = 0; x < Wid; x++)
- {
- int BlockX = (x - m_OriginX) * m_Zoom;
- int ChunkX = (BlockX >= 0) ? (BlockX / 16) : ((BlockX + 1) / 16 - 1);
- int RelX = BlockX - ChunkX * 16;
- if ((ChunkZ != CurChunkZ) || (ChunkX != CurChunkX))
- {
- CurChunkX = ChunkX;
- CurChunkZ = ChunkZ;
- switch (m_Cache.GetBiome(CurChunkX, CurChunkZ, CurBiomes))
- {
- case cBiomeSource::baLater:
- {
- res = true;
- // fallthrough:
- }
- case cBiomeSource::baNever:
- {
- for (int i = 0; i < ARRAYCOUNT(CurBiomes); i++)
- {
- CurBiomes[i] = biInvalidBiome;
- }
- break;
- }
- } // switch (Biome availability)
- }
- EMCSBiome Biome = cChunkDef::GetBiome(CurBiomes, RelX, RelZ);
- a_Pixmap.SetPixel(x, y, GetBiomeColor(Biome));
- } // for x
- } // for y
- return res;
-}
-
-
-
-
-
-int cBiomeRenderer::GetBiomeColor(EMCSBiome a_Biome)
-{
- if ((a_Biome < 0) || (a_Biome >= ARRAYCOUNT(g_BiomeColors)))
- {
- return 0xff0000;
- }
- return g_BiomeColors[a_Biome];
-}
-
-
-
-
-
-void cBiomeRenderer::MoveViewBy(int a_OffsX, int a_OffsY)
-{
- m_OriginX += a_OffsX;
- m_OriginY += a_OffsY;
-}
-
-
-
-
diff --git a/Tools/BiomeVisualiser/BiomeRenderer.h b/Tools/BiomeVisualiser/BiomeRenderer.h
deleted file mode 100644
index 752b61811..000000000
--- a/Tools/BiomeVisualiser/BiomeRenderer.h
+++ /dev/null
@@ -1,55 +0,0 @@
-
-// BiomeRenderer.h
-
-// Declares the cBiomeRenderer class representing the rendering engine
-
-
-
-
-
-#pragma once
-
-#include "BiomeCache.h"
-
-
-
-
-
-// fwd: Pixmap.h
-class cPixmap;
-
-
-
-
-
-class cBiomeRenderer
-{
-public:
- cBiomeRenderer(void);
-
- void SetSource(cBiomeSource * a_Source); // Takes ownership of the source
-
- /// Renders the biomes into the given pixmap. Returns true if some biome data was missing and can be retrieved later
- bool Render(cPixmap & a_Pixmap);
-
- /// Returns the RGB color value for the specified biome
- int GetBiomeColor(EMCSBiome a_Biome);
-
- void MoveViewBy(int a_OffsX, int a_OffsY);
-
- void SetZoom(int a_NewZoom)
- {
- m_Zoom = a_NewZoom;
- }
-
-protected:
- cBiomeCache m_Cache;
-
- int m_OriginX;
- int m_OriginY;
- int m_Zoom;
-} ;
-
-
-
-
diff --git a/Tools/BiomeVisualiser/BiomeSource.h b/Tools/BiomeVisualiser/BiomeSource.h
deleted file mode 100644
index 4a5153457..000000000
--- a/Tools/BiomeVisualiser/BiomeSource.h
+++ /dev/null
@@ -1,37 +0,0 @@
-
-// BiomeSource.h
-
-// Declares the cBiomeSource abstract class used as an interface for getting biomes from any source
-
-#pragma once
-
-
-
-
-
-#include "ChunkDef.h"
-
-
-
-
-
-class cBiomeSource abstract
-{
-public:
- enum eAvailability
- {
- baNow, // Data returned now
- baLater, // Data not returned, but will be available later, try again after a while
- baNever, // Data not returned, will not be available at all
- } ;
-
- /// Fills a_Biomes with the biomes for the chunk specified
- virtual eAvailability GetBiome(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_Biomes) = 0;
-
- /// Used to inform the source about the view area that will be queried in the near future.
- virtual void HintViewArea(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ) = 0;
-} ;
-
-
-
-
diff --git a/Tools/BiomeVisualiser/BiomeViewWnd.cpp b/Tools/BiomeVisualiser/BiomeViewWnd.cpp
deleted file mode 100644
index 7fb61c062..000000000
--- a/Tools/BiomeVisualiser/BiomeViewWnd.cpp
+++ /dev/null
@@ -1,247 +0,0 @@
-
-// BiomeViewWnd.cpp
-
-// Implements the cBiomeViewWnd class representing the window that displays biomes
-
-#include "Globals.h"
-#include "BiomeViewWnd.h"
-#include "BiomeCache.h"
-#include "GeneratorBiomeSource.h"
-#include "iniFile/iniFile.h"
-
-
-
-
-
-const int TIMER_RERENDER = 1200;
-
-
-
-
-
-cBiomeViewWnd::cBiomeViewWnd(void) :
- m_Wnd(NULL),
- m_Thunk(&cBiomeViewWnd::WndProc, this),
- m_IsLButtonDown(false)
-{
-}
-
-
-
-
-
-bool cBiomeViewWnd::Create(HWND a_ParentWnd, LPCTSTR a_Title)
-{
- ASSERT(m_Wnd == NULL);
-
- InitBiomeView();
-
- // Create a regular STATIC window, then override its window procedure with our own. No need for obnoxious RegisterWindowClass() stuff.
- m_Wnd = CreateWindow("STATIC", a_Title, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 400, 300, a_ParentWnd, NULL, GetModuleHandle(NULL), NULL);
- if (m_Wnd == NULL)
- {
- LOGERROR("Cannot create main window: %d", GetLastError());
- return false;
- }
- SetWindowLongPtr(m_Wnd, GWLP_WNDPROC, m_Thunk);
-
- return true;
-}
-
-
-
-
-
-void cBiomeViewWnd::InitBiomeView(void)
-{
- cIniFile IniFile;
- IniFile.ReadFile("world.ini");
- int Seed = IniFile.GetValueSetI("Generator", "Seed", 0);
- bool CacheOffByDefault = false;
- m_BiomeGen = cBiomeGen::CreateBiomeGen(IniFile, Seed, CacheOffByDefault);
- m_Renderer.SetSource(new cGeneratorBiomeSource(m_BiomeGen));
- IniFile.WriteFile("world.ini");
-}
-
-
-
-
-
-void cBiomeViewWnd::SetZoom(int a_NewZoom)
-{
- m_Renderer.SetZoom(a_NewZoom);
- Redraw();
-}
-
-
-
-
-
-void cBiomeViewWnd::Redraw(void)
-{
- if (m_Renderer.Render(m_Pixmap))
- {
- SetTimer(m_Wnd, TIMER_RERENDER, 200, NULL);
- }
- InvalidateRect(m_Wnd, NULL, FALSE);
-}
-
-
-
-
-
-LRESULT cBiomeViewWnd::WndProc(HWND a_Wnd, UINT a_Msg, WPARAM wParam, LPARAM lParam)
-{
- switch (a_Msg)
- {
- case WM_CHAR: return OnChar (wParam, lParam);
- case WM_CLOSE: return OnClose ();
- case WM_COMMAND: return OnCommand (wParam, lParam);
- case WM_LBUTTONDOWN: return OnLButtonDown(wParam, lParam);
- case WM_LBUTTONUP: return OnLButtonUp (wParam, lParam);
- case WM_MOUSEMOVE: return OnMouseMove (wParam, lParam);
- case WM_PAINT: return OnPaint ();
- case WM_TIMER: return OnTimer (wParam);
- }
- return ::DefWindowProc(a_Wnd, a_Msg, wParam, lParam);
-}
-
-
-
-
-
-LRESULT cBiomeViewWnd::OnChar(WPARAM wParam, LPARAM lParam)
-{
- switch (wParam)
- {
- case '1': SetZoom(1); break;
- case '2': SetZoom(2); break;
- case '3': SetZoom(3); break;
- case '4': SetZoom(4); break;
- case '5': SetZoom(5); break;
- case '6': SetZoom(6); break;
- case '7': SetZoom(7); break;
- case '8': SetZoom(8); break;
- case 27:
- {
- // Esc pressed, exit
- PostQuitMessage(0);
- break;
- }
- }
- return 0;
-}
-
-
-
-
-
-LRESULT cBiomeViewWnd::OnClose(void)
-{
- PostQuitMessage(0);
- return 0;
-}
-
-
-
-
-
-LRESULT cBiomeViewWnd::OnCommand(WPARAM wParam, LPARAM lParam)
-{
- // TODO: Handle menu commands, when we get menu
- return 0;
-}
-
-
-
-
-
-LRESULT cBiomeViewWnd::OnLButtonDown(WPARAM wParam, LPARAM lParam)
-{
- m_IsLButtonDown = true;
- GetCursorPos(&m_MouseDown);
- return 0;
-}
-
-
-
-
-
-LRESULT cBiomeViewWnd::OnMouseMove(WPARAM wParam, LPARAM lParam)
-{
- if (!m_IsLButtonDown)
- {
- return 0;
- }
- POINT pnt;
- GetCursorPos(&pnt);
- m_Renderer.MoveViewBy(pnt.x - m_MouseDown.x, pnt.y - m_MouseDown.y);
- m_MouseDown = pnt;
- Redraw();
- return 0;
-}
-
-
-
-
-
-LRESULT cBiomeViewWnd::OnLButtonUp(WPARAM wParam, LPARAM lParam)
-{
- OnMouseMove(wParam, lParam); // Last movement - if the mouse move hasn't been reported due to speed
- m_IsLButtonDown = false;
- InvalidateRect(m_Wnd, NULL, FALSE);
- return 0;
-}
-
-
-
-
-
-LRESULT cBiomeViewWnd::OnPaint(void)
-{
- PAINTSTRUCT ps;
- HDC DC = BeginPaint(m_Wnd, &ps);
-
- RECT rc;
- GetClientRect(m_Wnd, &rc);
- int Wid = rc.right - rc.left;
- int Hei = rc.bottom - rc.top;
- if ((m_Pixmap.GetWidth() != Wid) || (m_Pixmap.GetHeight() != Hei))
- {
- m_Pixmap.SetSize(Wid, Hei);
- if (m_Renderer.Render(m_Pixmap))
- {
- SetTimer(m_Wnd, TIMER_RERENDER, 200, NULL);
- }
- }
-
- m_Pixmap.DrawToDC(DC, 0, 0);
-
- EndPaint(m_Wnd, &ps);
- return 0;
-}
-
-
-
-
-
-LRESULT cBiomeViewWnd::OnTimer(WPARAM wParam)
-{
- switch (wParam)
- {
- case TIMER_RERENDER:
- {
- if (!m_Renderer.Render(m_Pixmap))
- {
- KillTimer(m_Wnd, TIMER_RERENDER);
- }
- InvalidateRect(m_Wnd, NULL, FALSE);
- break;
- }
- }
- return 0;
-}
-
-
-
-
diff --git a/Tools/BiomeVisualiser/BiomeViewWnd.h b/Tools/BiomeVisualiser/BiomeViewWnd.h
deleted file mode 100644
index 70c5e38f2..000000000
--- a/Tools/BiomeVisualiser/BiomeViewWnd.h
+++ /dev/null
@@ -1,69 +0,0 @@
-
-// BiomeViewWnd.h
-
-// Declares the cBiomeViewWnd class representing the window that displays biomes
-
-
-
-
-
-#pragma once
-
-#include "WndProcThunk.h"
-#include "BiomeRenderer.h"
-#include "BiomeCache.h"
-#include "Pixmap.h"
-
-
-
-
-
-// fwd:
-class cBiomeGen;
-
-
-
-
-
-class cBiomeViewWnd
-{
-public:
- cBiomeViewWnd(void);
-
- bool Create(HWND a_ParentWnd, LPCTSTR a_Title);
-
-protected:
- HWND m_Wnd;
- CWndProcThunk<cBiomeViewWnd> m_Thunk;
-
- cBiomeRenderer m_Renderer;
- cPixmap m_Pixmap;
-
- /// The generator that is to be visualised
- cBiomeGen * m_BiomeGen;
-
- bool m_IsLButtonDown;
- POINT m_MouseDown;
-
-
- void InitBiomeView(void);
-
- void SetZoom(int a_NewZoom);
- void Redraw(void);
-
- LRESULT WndProc(HWND a_Wnd, UINT a_Msg, WPARAM wParam, LPARAM lParam);
-
- // Message handlers:
- LRESULT OnChar (WPARAM wParam, LPARAM lParam);
- LRESULT OnClose (void);
- LRESULT OnCommand (WPARAM wParam, LPARAM lParam);
- LRESULT OnLButtonDown(WPARAM wParam, LPARAM lParam);
- LRESULT OnMouseMove (WPARAM wParam, LPARAM lParam);
- LRESULT OnLButtonUp (WPARAM wParam, LPARAM lParam);
- LRESULT OnPaint (void);
- LRESULT OnTimer (WPARAM wParam);
-} ;
-
-
-
-
diff --git a/Tools/BiomeVisualiser/BiomeVisualiser.cpp b/Tools/BiomeVisualiser/BiomeVisualiser.cpp
deleted file mode 100644
index a36111d77..000000000
--- a/Tools/BiomeVisualiser/BiomeVisualiser.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-
-// BiomeVisualiser.cpp
-
-// Implements the cBiomeVisualiser class representing the entire app. Also implements the WinMain() entrypoint
-
-#include "Globals.h"
-#include "time.h"
-#include "BiomeVisualiser.h"
-
-
-
-
-
-int WINAPI WinMain(HINSTANCE a_Instance, HINSTANCE a_PrevInstance, LPSTR a_CmdLine, int a_ShowCmd)
-{
- cBiomeVisualiser App;
- return App.Run();
-}
-
-
-
-
-
-cBiomeVisualiser::cBiomeVisualiser(void) :
- m_Logger(new cMCLogger(Printf("BiomeVisualiser_%08x.log", time(NULL))))
-{
-}
-
-
-
-
-
-int cBiomeVisualiser::Run(void)
-{
- if (!m_MainWnd.Create(GetDesktopWindow(), TEXT("BiomeVisualiser")))
- {
- LOGERROR("Cannot create main window: %d", GetLastError());
- return 1;
- }
-
- MSG msg;
- while (GetMessage(&msg, NULL, 0, 0))
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- } // while (GetMessage)
- return msg.lParam;
-}
-
-
-
-
diff --git a/Tools/BiomeVisualiser/BiomeVisualiser.h b/Tools/BiomeVisualiser/BiomeVisualiser.h
deleted file mode 100644
index 4f8ce7513..000000000
--- a/Tools/BiomeVisualiser/BiomeVisualiser.h
+++ /dev/null
@@ -1,31 +0,0 @@
-
-// BiomeVisualiser.h
-
-// Declares the cBiomeVisualiser class representing the entire application
-
-
-
-
-
-#include "BiomeViewWnd.h"
-
-
-
-
-
-class cBiomeVisualiser
-{
-public:
- cBiomeVisualiser(void);
-
- int Run(void);
-
-protected:
- cBiomeViewWnd m_MainWnd;
-
- cMCLogger * m_Logger;
-} ;
-
-
-
-
diff --git a/Tools/BiomeVisualiser/BiomeVisualiser.sln b/Tools/BiomeVisualiser/BiomeVisualiser.sln
deleted file mode 100644
index bdfb586b1..000000000
--- a/Tools/BiomeVisualiser/BiomeVisualiser.sln
+++ /dev/null
@@ -1,23 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 10.00
-# Visual C++ Express 2008
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BiomeVisualiser", "BiomeVisualiser.vcproj", "{6DF3D88B-AD47-45B6-B831-1BDE74F86B5C}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Win32 = Debug|Win32
- Release profiled|Win32 = Release profiled|Win32
- Release|Win32 = Release|Win32
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {6DF3D88B-AD47-45B6-B831-1BDE74F86B5C}.Debug|Win32.ActiveCfg = Debug|Win32
- {6DF3D88B-AD47-45B6-B831-1BDE74F86B5C}.Debug|Win32.Build.0 = Debug|Win32
- {6DF3D88B-AD47-45B6-B831-1BDE74F86B5C}.Release profiled|Win32.ActiveCfg = Release profiled|Win32
- {6DF3D88B-AD47-45B6-B831-1BDE74F86B5C}.Release profiled|Win32.Build.0 = Release profiled|Win32
- {6DF3D88B-AD47-45B6-B831-1BDE74F86B5C}.Release|Win32.ActiveCfg = Release|Win32
- {6DF3D88B-AD47-45B6-B831-1BDE74F86B5C}.Release|Win32.Build.0 = Release|Win32
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
-EndGlobal
diff --git a/Tools/BiomeVisualiser/BiomeVisualiser.vcproj b/Tools/BiomeVisualiser/BiomeVisualiser.vcproj
deleted file mode 100644
index 3de564ad4..000000000
--- a/Tools/BiomeVisualiser/BiomeVisualiser.vcproj
+++ /dev/null
@@ -1,527 +0,0 @@
-<?xml version="1.0" encoding="windows-1250"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="9,00"
- Name="BiomeVisualiser"
- ProjectGUID="{6DF3D88B-AD47-45B6-B831-1BDE74F86B5C}"
- RootNamespace="BiomeVisualiser"
- Keyword="Win32Proj"
- TargetFrameworkVersion="196613"
- >
- <Platforms>
- <Platform
- Name="Win32"
- />
- </Platforms>
- <ToolFiles>
- </ToolFiles>
- <Configurations>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory="$(SolutionDir)$(ConfigurationName)"
- IntermediateDirectory="$(ConfigurationName)"
- ConfigurationType="1"
- CharacterSet="2"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories="../../src;../../lib"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
- MinimalRebuild="true"
- BasicRuntimeChecks="3"
- RuntimeLibrary="1"
- UsePrecompiledHeader="2"
- PrecompiledHeaderThrough="Globals.h"
- WarningLevel="3"
- DebugInformationFormat="4"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="ws2_32.lib"
- LinkIncremental="2"
- GenerateDebugInformation="true"
- SubSystem="2"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory="$(SolutionDir)$(ConfigurationName)"
- IntermediateDirectory="$(ConfigurationName)"
- ConfigurationType="1"
- CharacterSet="2"
- WholeProgramOptimization="1"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- InlineFunctionExpansion="2"
- EnableIntrinsicFunctions="true"
- FavorSizeOrSpeed="1"
- AdditionalIncludeDirectories="../../src;../../lib"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
- RuntimeLibrary="0"
- EnableFunctionLevelLinking="true"
- EnableEnhancedInstructionSet="2"
- UsePrecompiledHeader="2"
- PrecompiledHeaderThrough="Globals.h"
- WarningLevel="3"
- DebugInformationFormat="3"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="ws2_32.lib"
- LinkIncremental="1"
- GenerateDebugInformation="true"
- SubSystem="2"
- OptimizeReferences="2"
- EnableCOMDATFolding="2"
- TargetMachine="1"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- <Configuration
- Name="Release profiled|Win32"
- OutputDirectory="$(SolutionDir)$(ConfigurationName)"
- IntermediateDirectory="$(ConfigurationName)"
- ConfigurationType="1"
- CharacterSet="2"
- WholeProgramOptimization="1"
- >
- <Tool
- Name="VCPreBuildEventTool"
- />
- <Tool
- Name="VCCustomBuildTool"
- />
- <Tool
- Name="VCXMLDataGeneratorTool"
- />
- <Tool
- Name="VCWebServiceProxyGeneratorTool"
- />
- <Tool
- Name="VCMIDLTool"
- />
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- InlineFunctionExpansion="2"
- EnableIntrinsicFunctions="true"
- FavorSizeOrSpeed="1"
- AdditionalIncludeDirectories="../../src;../../lib"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
- RuntimeLibrary="0"
- EnableFunctionLevelLinking="true"
- EnableEnhancedInstructionSet="2"
- UsePrecompiledHeader="2"
- PrecompiledHeaderThrough="Globals.h"
- WarningLevel="3"
- DebugInformationFormat="3"
- />
- <Tool
- Name="VCManagedResourceCompilerTool"
- />
- <Tool
- Name="VCResourceCompilerTool"
- />
- <Tool
- Name="VCPreLinkEventTool"
- />
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="ws2_32.lib"
- LinkIncremental="1"
- GenerateDebugInformation="true"
- SubSystem="2"
- OptimizeReferences="2"
- EnableCOMDATFolding="2"
- TargetMachine="1"
- Profile="true"
- />
- <Tool
- Name="VCALinkTool"
- />
- <Tool
- Name="VCManifestTool"
- />
- <Tool
- Name="VCXDCMakeTool"
- />
- <Tool
- Name="VCBscMakeTool"
- />
- <Tool
- Name="VCFxCopTool"
- />
- <Tool
- Name="VCAppVerifierTool"
- />
- <Tool
- Name="VCPostBuildEventTool"
- />
- </Configuration>
- </Configurations>
- <References>
- </References>
- <Files>
- <Filter
- Name="Source Files"
- Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
- UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
- >
- <File
- RelativePath=".\BiomeCache.cpp"
- >
- </File>
- <File
- RelativePath=".\BiomeCache.h"
- >
- </File>
- <File
- RelativePath=".\BiomeColors.cpp"
- >
- </File>
- <File
- RelativePath=".\BiomeColors.h"
- >
- </File>
- <File
- RelativePath=".\BiomeRenderer.cpp"
- >
- </File>
- <File
- RelativePath=".\BiomeRenderer.h"
- >
- </File>
- <File
- RelativePath=".\BiomeSource.h"
- >
- </File>
- <File
- RelativePath=".\BiomeViewWnd.cpp"
- >
- </File>
- <File
- RelativePath=".\BiomeViewWnd.h"
- >
- </File>
- <File
- RelativePath=".\BiomeVisualiser.cpp"
- >
- </File>
- <File
- RelativePath=".\BiomeVisualiser.h"
- >
- </File>
- <File
- RelativePath=".\GeneratorBiomeSource.h"
- >
- </File>
- <File
- RelativePath=".\Pixmap.cpp"
- >
- </File>
- <File
- RelativePath=".\Pixmap.h"
- >
- </File>
- <File
- RelativePath=".\Timer.h"
- >
- </File>
- <File
- RelativePath=".\WndProcThunk.h"
- >
- </File>
- <Filter
- Name="Shared"
- >
- <File
- RelativePath="..\..\src\BiomeDef.cpp"
- >
- </File>
- <File
- RelativePath="..\..\src\BiomeDef.h"
- >
- </File>
- <File
- RelativePath="..\..\src\BlockID.cpp"
- >
- </File>
- <File
- RelativePath="..\..\src\BlockID.h"
- >
- </File>
- <File
- RelativePath="..\..\src\ChunkDef.h"
- >
- </File>
- <File
- RelativePath="..\..\src\Enchantments.cpp"
- >
- </File>
- <File
- RelativePath="..\..\src\Enchantments.h"
- >
- </File>
- <File
- RelativePath="..\..\src\WorldStorage\FastNBT.cpp"
- >
- </File>
- <File
- RelativePath="..\..\src\WorldStorage\FastNBT.h"
- >
- </File>
- <File
- RelativePath="..\..\src\FastRandom.cpp"
- >
- </File>
- <File
- RelativePath="..\..\src\FastRandom.h"
- >
- </File>
- <File
- RelativePath="..\..\src\Globals.cpp"
- >
- <FileConfiguration
- Name="Debug|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- UsePrecompiledHeader="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- UsePrecompiledHeader="1"
- />
- </FileConfiguration>
- <FileConfiguration
- Name="Release profiled|Win32"
- >
- <Tool
- Name="VCCLCompilerTool"
- UsePrecompiledHeader="1"
- />
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\..\src\Globals.h"
- >
- </File>
- <File
- RelativePath="..\..\src\Item.h"
- >
- </File>
- <File
- RelativePath="..\..\src\Log.cpp"
- >
- </File>
- <File
- RelativePath="..\..\src\Log.h"
- >
- </File>
- <File
- RelativePath="..\..\src\MCLogger.cpp"
- >
- </File>
- <File
- RelativePath="..\..\src\MCLogger.h"
- >
- </File>
- <File
- RelativePath="..\..\src\Noise.cpp"
- >
- </File>
- <File
- RelativePath="..\..\src\Noise.h"
- >
- </File>
- <File
- RelativePath="..\..\src\Noise.inc"
- >
- </File>
- <File
- RelativePath="..\..\src\StringUtils.cpp"
- >
- </File>
- <File
- RelativePath="..\..\src\StringUtils.h"
- >
- </File>
- <File
- RelativePath="..\..\src\VoronoiMap.cpp"
- >
- </File>
- <File
- RelativePath="..\..\src\VoronoiMap.h"
- >
- </File>
- <Filter
- Name="OSSupport"
- >
- <File
- RelativePath="..\..\src\OSSupport\CriticalSection.cpp"
- >
- </File>
- <File
- RelativePath="..\..\src\OSSupport\CriticalSection.h"
- >
- </File>
- <File
- RelativePath="..\..\src\OSSupport\Event.cpp"
- >
- </File>
- <File
- RelativePath="..\..\src\OSSupport\Event.h"
- >
- </File>
- <File
- RelativePath="..\..\src\OSSupport\File.cpp"
- >
- </File>
- <File
- RelativePath="..\..\src\OSSupport\File.h"
- >
- </File>
- <File
- RelativePath="..\..\src\OSSupport\IsThread.cpp"
- >
- </File>
- <File
- RelativePath="..\..\src\OSSupport\IsThread.h"
- >
- </File>
- <File
- RelativePath="..\..\src\OSSupport\Sleep.h"
- >
- </File>
- </Filter>
- <Filter
- Name="Generating"
- >
- <File
- RelativePath="..\..\src\Generating\BioGen.cpp"
- >
- </File>
- <File
- RelativePath="..\..\src\Generating\BioGen.h"
- >
- </File>
- <File
- RelativePath="..\..\src\Generating\ComposableGenerator.h"
- >
- </File>
- </Filter>
- <Filter
- Name="iniFile"
- >
- <File
- RelativePath="..\..\lib\iniFile\iniFile.cpp"
- >
- </File>
- <File
- RelativePath="..\..\lib\iniFile\iniFile.h"
- >
- </File>
- </Filter>
- </Filter>
- </Filter>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
diff --git a/Tools/BiomeVisualiser/GeneratorBiomeSource.h b/Tools/BiomeVisualiser/GeneratorBiomeSource.h
deleted file mode 100644
index 751aed245..000000000
--- a/Tools/BiomeVisualiser/GeneratorBiomeSource.h
+++ /dev/null
@@ -1,42 +0,0 @@
-
-// GeneratorBiomeSource.h
-
-// Declares the cGeneratorBiomeSource that adapts a cBiomeGen into a cBiomeSource
-
-#include "../src/Generating/BioGen.h"
-#include "BiomeSource.h"
-
-
-
-
-
-class cGeneratorBiomeSource :
- public cBiomeSource
-{
-public:
- cGeneratorBiomeSource(cBiomeGen * a_Generator) : m_Generator(a_Generator) {} // Takes ownership of the generator ptr
-
- ~cGeneratorBiomeSource()
- {
- delete m_Generator;
- }
-
- // cBiomeSource overrides:
- virtual eAvailability GetBiome(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_Biomes) override
- {
- m_Generator->GenBiomes(a_ChunkX, a_ChunkZ, a_Biomes);
- return baNow;
- }
-
- virtual void HintViewArea(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ) override
- {
- // Nothing needed
- }
-
-protected:
- cBiomeGen * m_Generator;
-} ;
-
-
-
-
diff --git a/Tools/BiomeVisualiser/Pixmap.cpp b/Tools/BiomeVisualiser/Pixmap.cpp
deleted file mode 100644
index 1a80cf465..000000000
--- a/Tools/BiomeVisualiser/Pixmap.cpp
+++ /dev/null
@@ -1,120 +0,0 @@
-
-// Pixmap.cpp
-
-// Implements the cPixmap class that represents a RGB pixmap and allows simple operations on it
-
-#include "Globals.h"
-#include "Pixmap.h"
-
-
-
-
-
-cPixmap::cPixmap(void) :
- m_Width(0),
- m_Height(0),
- m_Stride(0),
- m_Pixels(NULL)
-{
-}
-
-
-
-
-
-cPixmap::cPixmap(int a_Width, int a_Height) :
- m_Width(0),
- m_Height(0),
- m_Stride(0),
- m_Pixels(NULL)
-{
- SetSize(a_Width, a_Height);
-}
-
-
-
-
-
-cPixmap::~cPixmap()
-{
- delete m_Pixels;
-}
-
-
-
-
-
-void cPixmap::SetSize(int a_Width, int a_Height)
-{
- delete m_Pixels;
- m_Pixels = new int[a_Width * a_Height];
- m_Width = a_Width;
- m_Height = a_Height;
- m_Stride = m_Width; // Currently we don't need a special stride value, but let's support it for the future :)
-}
-
-
-
-
-
-void cPixmap::SetPixel(int a_X, int a_Y, int a_Color)
-{
- ASSERT(a_X >= 0);
- ASSERT(a_X < m_Width);
- ASSERT(a_Y >= 0);
- ASSERT(a_Y < m_Height);
-
- m_Pixels[a_X + a_Y * m_Stride] = a_Color;
-}
-
-
-
-
-
-int cPixmap::GetPixel(int a_X, int a_Y) const
-{
- ASSERT(a_X >= 0);
- ASSERT(a_X < m_Width);
- ASSERT(a_Y >= 0);
- ASSERT(a_Y < m_Height);
-
- return m_Pixels[a_X + a_Y * m_Stride];
-}
-
-
-
-
-
-void cPixmap::Fill(int a_Color)
-{
- int NumElements = m_Height * m_Stride;
- for (int i = 0; i < NumElements; i++)
- {
- m_Pixels[i] = a_Color;
- }
-}
-
-
-
-
-
-void cPixmap::DrawToDC(HDC a_DC, int a_OriginX, int a_OriginY)
-{
- BITMAPINFO bmi;
- bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
- bmi.bmiHeader.biWidth = m_Width;
- bmi.bmiHeader.biHeight = -m_Height; // Negative, we are top-down, unlike BMPs
- bmi.bmiHeader.biPlanes = 1;
- bmi.bmiHeader.biBitCount = 32;
- bmi.bmiHeader.biCompression = BI_RGB;
- bmi.bmiHeader.biSizeImage = m_Stride * m_Height * 4;
- bmi.bmiHeader.biXPelsPerMeter = 1440;
- bmi.bmiHeader.biYPelsPerMeter = 1440;
- bmi.bmiHeader.biClrUsed = 0;
- bmi.bmiHeader.biClrImportant = 0;
- SetDIBitsToDevice(a_DC, a_OriginX, a_OriginY, m_Width, m_Height, 0, 0, 0, m_Height, m_Pixels, &bmi, DIB_RGB_COLORS);
-}
-
-
-
-
diff --git a/Tools/BiomeVisualiser/Pixmap.h b/Tools/BiomeVisualiser/Pixmap.h
deleted file mode 100644
index e50f6e946..000000000
--- a/Tools/BiomeVisualiser/Pixmap.h
+++ /dev/null
@@ -1,39 +0,0 @@
-
-// Pixmap.h
-
-// Declares a cPixmap class that represents a RGB pixmap and allows simple operations on it
-
-#pragma once
-
-
-
-
-
-class cPixmap
-{
-public:
- cPixmap(void);
- cPixmap(int a_Width, int a_Height);
- ~cPixmap();
-
- void SetSize(int a_Width, int a_Height);
-
- int GetWidth (void) const { return m_Width; }
- int GetHeight(void) const { return m_Height; }
-
- void SetPixel(int a_X, int a_Y, int a_Color);
- int GetPixel(int a_X, int a_Y) const;
- void Fill(int a_Color);
-
- void DrawToDC(HDC a_DC, int a_OriginX, int a_OriginY);
-
-protected:
- int m_Width;
- int m_Height;
- int m_Stride;
- int * m_Pixels;
-} ;
-
-
-
-
diff --git a/Tools/BiomeVisualiser/Timer.h b/Tools/BiomeVisualiser/Timer.h
deleted file mode 100644
index 78c4b42c7..000000000
--- a/Tools/BiomeVisualiser/Timer.h
+++ /dev/null
@@ -1,40 +0,0 @@
-
-// Timer.h
-
-// Declares the cTimer class representing a RAII class that measures time from its creation till its destruction
-
-
-
-
-
-#pragma once
-
-#include "time.h"
-
-
-
-
-
-class cTimer
-{
-public:
- cTimer(const AString & a_Title) :
- m_Title(a_Title),
- m_StartTime(clock())
- {
- }
-
- ~cTimer()
- {
- clock_t NumTicks = clock() - m_StartTime;
- LOG("%s took %d ticks (%.02f sec)", m_Title.c_str(), NumTicks, (double)NumTicks / CLOCKS_PER_SEC);
- }
-
-protected:
- AString m_Title;
- clock_t m_StartTime;
-} ;
-
-
-
-
diff --git a/Tools/BiomeVisualiser/WndProcThunk.h b/Tools/BiomeVisualiser/WndProcThunk.h
deleted file mode 100644
index da995eb5f..000000000
--- a/Tools/BiomeVisualiser/WndProcThunk.h
+++ /dev/null
@@ -1,143 +0,0 @@
-
-// WndProcThunk.h
-
-// Interfaces to the CWndProcThunk class responsible for WNDPROC class-thunking
-// For details, see http://www.hackcraft.net/cpp/windowsThunk/thiscall/
-// Also available is a CDlgProcThunk class doing the same work for DIALOGPROC
-
-// MD: Made NX-compat by allocating the code structure using VirtualAlloc(..., PAGE_EXECUTE_READWRITE)
-
-
-
-
-
-// fwd:
-template <class W> class CWndProcThunk;
-
-
-
-
-
-#ifndef WNDPROCTHUNK_H_INCLUDED
-#define WNDPROCTHUNK_H_INCLUDED
-
-
-
-
-template<typename To, typename From> inline To union_cast(From fr) throw()
-{
- union
- {
- From f;
- To t;
- } uc;
- uc.f = fr;
- return uc.t;
-}
-
-
-
-
-
-#pragma warning(push)
-#pragma warning(disable : 4355)
-
-#if defined(_M_IX86)
-
-#pragma pack(push,1)
-
-template <class W> class CWndProcThunk
-{
- typedef ::LRESULT (W::* WndProc)(::HWND, ::UINT, ::WPARAM, ::LPARAM);
- typedef CWndProcThunk ThisClass;
-
- struct SCode
- {
- BYTE m_mov; // mov ECX, m_this
- W * m_this; //
- BYTE m_jmp; // jmp m_relproc
- ptrdiff_t m_relproc; // relative jmp
- };
-
- SCode * Code;
-
-public:
- ThisClass(WndProc proc, W * obj)
- {
- Code = (SCode *)VirtualAlloc(NULL, sizeof(SCode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
- Code->m_mov = 0xB9,
- Code->m_this = obj,
- Code->m_jmp = 0xE9,
- Code->m_relproc = union_cast<char *>(proc) - reinterpret_cast<char *>(Code) - sizeof(*Code);
- ::FlushInstructionCache(::GetCurrentProcess(), Code, sizeof(*Code));
- }
-
- virtual ~CWndProcThunk()
- {
- VirtualFree(Code, sizeof(*Code), MEM_RELEASE);
- Code = NULL;
- }
-
- operator ::WNDPROC() const {return reinterpret_cast<::WNDPROC>(Code); }
- operator ::LONG_PTR() const {return reinterpret_cast<::LONG_PTR>(Code); }
-} ;
-
-
-
-
-
-template <class W> class CDlgProcThunk
-{
- typedef ::BOOL (W::* DlgProc)(::HWND, ::UINT, ::WPARAM, ::LPARAM);
- typedef CDlgProcThunk ThisClass;
-
- struct SCode
- {
- BYTE m_mov; // mov ECX, m_this
- W * m_this; //
- BYTE m_jmp; // jmp m_relproc
- ptrdiff_t m_relproc; // relative jmp
- };
-
- SCode * Code;
-
-public:
- CDlgProcThunk(DlgProc proc, W * obj)
- {
- Code = (SCode *)VirtualAlloc(NULL, sizeof(SCode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
- Code->m_mov = 0xB9,
- Code->m_this = obj,
- Code->m_jmp = 0xE9,
- Code->m_relproc = union_cast<char *>(proc) - reinterpret_cast<char *>(Code) - sizeof(*Code);
- ::FlushInstructionCache(::GetCurrentProcess(), Code, sizeof(*Code));
- }
-
- virtual ~CDlgProcThunk()
- {
- VirtualFree(Code, sizeof(*Code), MEM_RELEASE);
- Code = NULL;
- }
-
- operator ::DLGPROC() const {return reinterpret_cast<::DLGPROC>(Code); }
- operator ::LONG_PTR() const {return reinterpret_cast<::LONG_PTR>(Code); }
-} ;
-
-
-
-
-
- #pragma pack(pop)
-
-#else // _M_IX86
- #error Only X86 supported
-#endif
-
-
-
-
-
-#endif // WNDPROCTHUNK_H_INCLUDED
-
-
-
-
diff --git a/Tools/BiomeVisualiser/profile_run.cmd b/Tools/BiomeVisualiser/profile_run.cmd
deleted file mode 100644
index d4826d06a..000000000
--- a/Tools/BiomeVisualiser/profile_run.cmd
+++ /dev/null
@@ -1,70 +0,0 @@
-@echo off
-::
-:: Profiling using a MSVC standalone profiler
-::
-:: See http://www.codeproject.com/Articles/144643/Profiling-of-C-Applications-in-Visual-Studio-for-F for details
-::
-
-
-
-
-set pt="C:\Program Files\Microsoft Visual Studio 9.0\Team Tools\Performance Tools"
-set appdir="Release profiled"
-set app="Release profiled\BiomeVisualiser.exe"
-set args=""
-
-:: outputdir is relative to appdir!
-set outputdir=Profiling
-set output=profile.vsp
-
-
-
-
-
-::Create the output directory, if it didn't exist
-mkdir %outputdir%
-
-
-
-
-
-:: Start the profiler
-%pt%\vsperfcmd /start:sample /output:%outputdir%\%output%
-if errorlevel 1 goto haderror
-
-:: Launch the application via the profiler
-%pt%\vsperfcmd /launch:%app% /args:%args%
-if errorlevel 1 goto haderror
-
-:: Shut down the profiler (this command waits, until the application is terminated)
-%pt%\vsperfcmd /shutdown
-if errorlevel 1 goto haderror
-
-
-
-
-
-:: cd to outputdir, so that the reports are generated there
-cd %outputdir%
-
-:: generate the report files (.csv)
-%pt%\vsperfreport /summary:all %output% /symbolpath:"srv*C:\Programovani\Symbols*http://msdl.microsoft.com/download/symbols"
-if errorlevel 1 goto haderror
-
-
-
-
-
-goto finished
-
-
-
-
-:haderror
-echo An error was encountered
-pause
-
-
-
-
-:finished
diff --git a/Tools/QtBiomeVisualiser/.gitignore b/Tools/QtBiomeVisualiser/.gitignore
new file mode 100644
index 000000000..c1b62a8a7
--- /dev/null
+++ b/Tools/QtBiomeVisualiser/.gitignore
@@ -0,0 +1,2 @@
+*.pro.user
+*.pro.user.*
diff --git a/Tools/QtBiomeVisualiser/BiomeView.cpp b/Tools/QtBiomeVisualiser/BiomeView.cpp
new file mode 100644
index 000000000..bbaccb369
--- /dev/null
+++ b/Tools/QtBiomeVisualiser/BiomeView.cpp
@@ -0,0 +1,427 @@
+#include "Globals.h"
+#include "BiomeView.h"
+#include "Chunk.h"
+#include <QPainter>
+#include <QResizeEvent>
+
+
+
+
+
+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_IsMouseDragging(false),
+ m_MouseWheelDelta(0)
+{
+ // Create the image used for undefined chunks:
+ int offset = 0;
+ for (int y = 0; y < 16; y++)
+ {
+ for (int x = 0; x < 16; x++)
+ {
+ uchar color = (((x & 8) ^ (y & 8)) == 0) ? 0x44 : 0x88;
+ m_EmptyChunkImage[offset++] = color;
+ m_EmptyChunkImage[offset++] = color;
+ m_EmptyChunkImage[offset++] = color;
+ m_EmptyChunkImage[offset++] = 0xff;
+ }
+ }
+
+ // Create the startup image:
+ redraw();
+
+ // Add a chunk-update callback mechanism:
+ connect(&m_Cache, SIGNAL(chunkAvailable(int, int)), this, SLOT(chunkAvailable(int, int)));
+
+ // Allow keyboard interaction:
+ setFocusPolicy(Qt::StrongFocus);
+}
+
+
+
+
+QSize BiomeView::minimumSizeHint() const
+{
+ return QSize(300, 300);
+}
+
+
+
+
+
+QSize BiomeView::sizeHint() const
+{
+ return QSize(800, 600);
+}
+
+
+
+
+
+void BiomeView::setChunkSource(std::shared_ptr<ChunkSource> a_ChunkSource)
+{
+ // Replace the source in the cache:
+ m_Cache.setChunkSource(a_ChunkSource);
+
+ // Redraw with the new source:
+ redraw();
+}
+
+
+
+
+
+void BiomeView::redraw()
+{
+ if (!hasData())
+ {
+ // No data means no image is displayed, no need to compose:
+ update();
+ return;
+ }
+
+ int chunksize = 16 * m_Zoom;
+
+ // first find the center block position
+ int centerchunkx = floor(m_X / 16);
+ int centerchunkz = floor(m_Z / 16);
+ // and the center of the screen
+ int centerx = m_Image.width() / 2;
+ int centery = m_Image.height() / 2;
+ // and align for panning
+ centerx -= (m_X - centerchunkx * 16) * m_Zoom;
+ centery -= (m_Z - centerchunkz * 16) * m_Zoom;
+ // now calculate the topleft block on the screen
+ int startx = centerchunkx - centerx / chunksize - 1;
+ int startz = centerchunkz - centery / chunksize - 1;
+ // and the dimensions of the screen in blocks
+ int blockswide = m_Image.width() / chunksize + 3;
+ int blockstall = m_Image.height() / chunksize + 3;
+
+ for (int z = startz; z < startz + blockstall; z++)
+ {
+ for (int x = startx; x < startx + blockswide; x++)
+ {
+ drawChunk(x, z);
+ }
+ }
+ update();
+}
+
+
+
+
+
+void BiomeView::chunkAvailable(int a_ChunkX, int a_ChunkZ)
+{
+ drawChunk(a_ChunkX, a_ChunkZ);
+ update();
+}
+
+
+
+
+
+void BiomeView::reload()
+{
+ if (!hasData())
+ {
+ return;
+ }
+ m_Cache.reload();
+
+ redraw();
+}
+
+
+
+
+
+void BiomeView::drawChunk(int a_ChunkX, int a_ChunkZ)
+{
+ if (!hasData())
+ {
+ return;
+ }
+
+ //fetch the chunk:
+ ChunkPtr chunk = m_Cache.fetch(a_ChunkX, a_ChunkZ);
+
+ // Figure out where on the screen this chunk should be drawn:
+ // first find the center chunk
+ int centerchunkx = floor(m_X / 16);
+ int centerchunkz = floor(m_Z / 16);
+ // and the center chunk screen coordinates
+ int centerx = m_Image.width() / 2;
+ int centery = m_Image.height() / 2;
+ // which need to be shifted to account for panning inside that chunk
+ centerx -= (m_X - centerchunkx * 16) * m_Zoom;
+ centery -= (m_Z - centerchunkz * 16) * m_Zoom;
+ // centerx,y now points to the top left corner of the center chunk
+ // so now calculate our x,y in relation
+ double chunksize = 16 * m_Zoom;
+ centerx += (a_ChunkX - centerchunkx) * chunksize;
+ centery += (a_ChunkZ - centerchunkz) * chunksize;
+
+ int srcoffset = 0;
+ uchar * bits = m_Image.bits();
+ int imgstride = m_Image.bytesPerLine();
+
+ int skipx = 0,skipy = 0;
+ int blockwidth = chunksize, blockheight = chunksize;
+ // now if we're off the screen we need to crop
+ if (centerx < 0)
+ {
+ skipx = -centerx;
+ centerx = 0;
+ }
+ if (centery < 0)
+ {
+ skipy = -centery;
+ centery = 0;
+ }
+ // or the other side, we need to trim
+ if (centerx + blockwidth > m_Image.width())
+ {
+ blockwidth = m_Image.width() - centerx;
+ }
+ if (centery + blockheight > m_Image.height())
+ {
+ blockheight = m_Image.height() - centery;
+ }
+ if ((blockwidth <= 0) || (skipx >= blockwidth))
+ {
+ return;
+ }
+ int imgoffset = centerx * 4 + centery * imgstride;
+
+ // If the chunk is valid, use its data; otherwise use the empty placeholder:
+ const uchar * src = m_EmptyChunkImage;
+ if (chunk.get() != nullptr)
+ {
+ src = chunk->getImage();
+ }
+
+ // Blit or scale-blit the image:
+ for (int z = skipy; z < blockheight; z++, imgoffset += imgstride)
+ {
+ srcoffset = floor((double)z / m_Zoom) * 16 * 4;
+ if (m_Zoom == 1.0)
+ {
+ memcpy(bits + imgoffset, src + srcoffset + skipx * 4, (blockwidth - skipx) * 4);
+ }
+ else
+ {
+ int xofs = 0;
+ for (int x = skipx; x < blockwidth; x++, xofs +=4)
+ {
+ memcpy(bits + imgoffset + xofs, src + srcoffset + (int)floor((double)x / m_Zoom) * 4, 4);
+ }
+ }
+ }
+}
+
+
+
+
+
+void BiomeView::resizeEvent(QResizeEvent * a_Event)
+{
+ m_Image = QImage(a_Event->size(), QImage::Format_RGB32);
+ redraw();
+}
+
+
+
+
+
+void BiomeView::paintEvent(QPaintEvent * a_Event)
+{
+ QPainter p(this);
+ if (hasData())
+ {
+ p.drawImage(QPoint(0, 0), m_Image);
+ }
+ else
+ {
+ p.drawText(a_Event->rect(), Qt::AlignCenter, "No chunk source selected");
+ }
+ p.end();
+}
+
+
+
+
+
+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();
+}
+
+
+
+
diff --git a/Tools/QtBiomeVisualiser/BiomeView.h b/Tools/QtBiomeVisualiser/BiomeView.h
new file mode 100644
index 000000000..86af8bcaf
--- /dev/null
+++ b/Tools/QtBiomeVisualiser/BiomeView.h
@@ -0,0 +1,99 @@
+#pragma once
+
+#include <QWidget>
+#include "ChunkCache.h"
+#include "ChunkSource.h"
+
+
+
+
+
+class BiomeView :
+ public QWidget
+{
+ typedef QWidget super;
+ Q_OBJECT
+
+public:
+ explicit BiomeView(QWidget * parent = NULL);
+
+ QSize minimumSizeHint() const;
+ QSize sizeHint() const;
+
+ /** Replaces the chunk source used by the biome view to get the chunk biome data.
+ The entire view is then invalidated and regenerated. */
+ void setChunkSource(std::shared_ptr<ChunkSource> a_ChunkSource);
+
+signals:
+
+public slots:
+ /** Redraw the entire widget area. */
+ void redraw();
+
+ /** 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;
+ 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];
+
+
+ /** Draws the specified chunk into m_Image */
+ void drawChunk(int a_ChunkX, int a_ChunkZ);
+
+ /** Returns true iff the biome view has been initialized to contain proper biome data. */
+ bool hasData(void) const { return m_Cache.hasData(); }
+
+ /** Called when the widget is resized */
+ virtual void resizeEvent(QResizeEvent *) override;
+
+ /** Paints the entire widget */
+ virtual void paintEvent(QPaintEvent *) override;
+
+ /** 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();
+};
+
+
+
+
+
diff --git a/Tools/QtBiomeVisualiser/Chunk.cpp b/Tools/QtBiomeVisualiser/Chunk.cpp
new file mode 100644
index 000000000..d3419af9c
--- /dev/null
+++ b/Tools/QtBiomeVisualiser/Chunk.cpp
@@ -0,0 +1,36 @@
+#include "Globals.h"
+#include "Globals.h"
+#include "Chunk.h"
+
+
+
+
+
+Chunk::Chunk() :
+ m_IsValid(false)
+{
+}
+
+
+
+
+
+const uchar * Chunk::getImage(void) const
+{
+ ASSERT(m_IsValid);
+ return m_Image;
+}
+
+
+
+
+
+void Chunk::setImage(const Image & a_Image)
+{
+ memcpy(m_Image, a_Image, sizeof(a_Image));
+ m_IsValid = true;
+}
+
+
+
+
diff --git a/Tools/QtBiomeVisualiser/Chunk.h b/Tools/QtBiomeVisualiser/Chunk.h
new file mode 100644
index 000000000..03e7bd1b3
--- /dev/null
+++ b/Tools/QtBiomeVisualiser/Chunk.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include <qglobal.h>
+
+
+
+
+
+class Chunk
+{
+public:
+ /** The type used for storing image data for a chunk. */
+ typedef uchar Image[16 * 16 * 4];
+
+
+ Chunk(void);
+
+ /** Returns true iff the chunk data is valid - loaded or generated. */
+ bool isValid(void) const { return m_IsValid; }
+
+ /** Returns the image of the chunk's biomes. Assumes that the chunk is valid. */
+ const uchar * getImage(void) const;
+
+ /** Sets the image data for this chunk. */
+ void setImage(const Image & a_Image);
+
+protected:
+ /** Flag that specifies if the chunk data is valid - loaded or generated. */
+ bool m_IsValid;
+
+ /** Cached rendered image of this chunk's biomes. Updated in render(). */
+ Image m_Image;
+};
+
+typedef std::shared_ptr<Chunk> ChunkPtr;
+
+
+
+
+
diff --git a/Tools/QtBiomeVisualiser/ChunkCache.cpp b/Tools/QtBiomeVisualiser/ChunkCache.cpp
new file mode 100644
index 000000000..05c267d30
--- /dev/null
+++ b/Tools/QtBiomeVisualiser/ChunkCache.cpp
@@ -0,0 +1,126 @@
+#include "Globals.h"
+#include "ChunkCache.h"
+#include <QMutexLocker>
+#include <QThreadPool>
+#include "ChunkSource.h"
+#include "ChunkLoader.h"
+
+
+
+
+
+ChunkCache::ChunkCache(QObject * parent) :
+ super(parent)
+{
+ m_Cache.setMaxCost(1024 * 1024 * 1024); // 1 GiB of memory for the cache
+}
+
+
+
+
+
+ChunkPtr ChunkCache::fetch(int a_ChunkX, int a_ChunkZ)
+{
+ // Retrieve from the cache:
+ quint32 hash = getChunkHash(a_ChunkX, a_ChunkZ);
+ ChunkPtr * res;
+ {
+ QMutexLocker lock(&m_Mtx);
+ res = m_Cache[hash];
+ // If succesful and chunk loaded, return the retrieved value:
+ if ((res != nullptr) && (*res)->isValid())
+ {
+ return *res;
+ }
+ }
+
+ // If the chunk is in cache but not valid, it means it has been already queued for rendering, do nothing now:
+ if (res != nullptr)
+ {
+ return ChunkPtr(nullptr);
+ }
+
+ // There's no such item in the cache, create it now:
+ res = new ChunkPtr(new Chunk);
+ if (res == nullptr)
+ {
+ return ChunkPtr(nullptr);
+ }
+ {
+ QMutexLocker lock(&m_Mtx);
+ m_Cache.insert(hash, res, sizeof(Chunk));
+ }
+
+ // Queue the chunk for rendering:
+ queueChunkRender(a_ChunkX, a_ChunkZ, *res);
+
+ // Return failure, the chunk is not yet rendered:
+ return ChunkPtr(nullptr);
+}
+
+
+
+
+
+void ChunkCache::setChunkSource(std::shared_ptr<ChunkSource> a_ChunkSource)
+{
+ // Replace the chunk source:
+ m_ChunkSource = a_ChunkSource;
+
+ // Clear the cache:
+ QMutexLocker lock(&m_Mtx);
+ m_Cache.clear();
+}
+
+
+
+
+
+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);
+}
+
+
+
+
+
+quint32 ChunkCache::getChunkHash(int a_ChunkX, int a_ChunkZ)
+{
+ // Simply join the two coords into a single int
+ // The coords will never be larger than 16-bits, so we can do this safely
+ return (((static_cast<quint32>(a_ChunkX) & 0xffff) << 16) | (static_cast<quint32>(a_ChunkZ) & 0xffff));
+}
+
+
+
+
+
+void ChunkCache::queueChunkRender(int a_ChunkX, int a_ChunkZ, ChunkPtr & a_Chunk)
+{
+ // Create a new loader task:
+ ChunkLoader * loader = new ChunkLoader(a_ChunkX, a_ChunkZ, a_Chunk, m_ChunkSource);
+ connect(loader, SIGNAL(loaded(int, int)), this, SLOT(gotChunk(int, int)));
+
+ QThreadPool::globalInstance()->start(loader);
+}
+
+
+
+
diff --git a/Tools/QtBiomeVisualiser/ChunkCache.h b/Tools/QtBiomeVisualiser/ChunkCache.h
new file mode 100644
index 000000000..0134bc7af
--- /dev/null
+++ b/Tools/QtBiomeVisualiser/ChunkCache.h
@@ -0,0 +1,71 @@
+#pragma once
+
+#include <QObject>
+#include <QCache>
+#include <QMutex>
+
+
+
+
+
+class Chunk;
+typedef std::shared_ptr<Chunk> ChunkPtr;
+
+class ChunkSource;
+
+
+
+
+
+/** Caches chunk data for reuse */
+class ChunkCache :
+ public QObject
+{
+ typedef QObject super;
+ Q_OBJECT
+
+public:
+ explicit ChunkCache(QObject * parent = NULL);
+
+ /** Retrieves the specified chunk from the cache.
+ Only returns valid chunks; if the chunk is invalid, queues it for rendering and returns an empty ptr. */
+ ChunkPtr fetch(int a_ChunkX, int a_ChunkZ);
+
+ /** Replaces the chunk source used by the biome view to get the chunk biome data.
+ The cache is then invalidated. */
+ void setChunkSource(std::shared_ptr<ChunkSource> a_ChunkSource);
+
+ /** Returns true iff the chunk source has been initialized. */
+ bool hasData() const { return (m_ChunkSource.get() != nullptr); }
+
+ /** Reloads the current chunk source. */
+ void reload();
+
+signals:
+ void chunkAvailable(int a_ChunkX, int a_ChunkZ);
+
+protected slots:
+ void gotChunk(int a_ChunkX, int a_ChunkZ);
+
+protected:
+ /** The cache of the chunks */
+ QCache<quint32, ChunkPtr> m_Cache;
+
+ /** Locks te cache against multithreaded access */
+ QMutex m_Mtx;
+
+ /** The source used to get the biome data. */
+ std::shared_ptr<ChunkSource> m_ChunkSource;
+
+
+ /** Returns the hash used by the chunk in the cache */
+ quint32 getChunkHash(int a_ChunkX, int a_ChunkZ);
+
+ /** Queues the specified chunk for rendering by m_ChunkSource. */
+ void queueChunkRender(int a_ChunkX, int a_ChunkZ, ChunkPtr & a_Chunk);
+};
+
+
+
+
+
diff --git a/Tools/QtBiomeVisualiser/ChunkLoader.cpp b/Tools/QtBiomeVisualiser/ChunkLoader.cpp
new file mode 100644
index 000000000..3d0123b23
--- /dev/null
+++ b/Tools/QtBiomeVisualiser/ChunkLoader.cpp
@@ -0,0 +1,29 @@
+#include "Globals.h"
+#include "ChunkLoader.h"
+#include "ChunkSource.h"
+
+
+
+
+
+ChunkLoader::ChunkLoader(int a_ChunkX, int a_ChunkZ, ChunkPtr a_Chunk, ChunkSourcePtr a_ChunkSource) :
+ m_ChunkX(a_ChunkX),
+ m_ChunkZ(a_ChunkZ),
+ m_Chunk(a_Chunk),
+ m_ChunkSource(a_ChunkSource)
+{
+}
+
+
+
+
+
+void ChunkLoader::run()
+{
+ m_ChunkSource->getChunkBiomes(m_ChunkX, m_ChunkZ, m_Chunk);
+ emit loaded(m_ChunkX, m_ChunkZ);
+}
+
+
+
+
diff --git a/Tools/QtBiomeVisualiser/ChunkLoader.h b/Tools/QtBiomeVisualiser/ChunkLoader.h
new file mode 100644
index 000000000..3565434b9
--- /dev/null
+++ b/Tools/QtBiomeVisualiser/ChunkLoader.h
@@ -0,0 +1,43 @@
+#pragma once
+#include <QObject>
+#include <QRunnable>
+
+
+
+
+// fwd:
+class Chunk;
+typedef std::shared_ptr<Chunk> ChunkPtr;
+
+class ChunkSource;
+typedef std::shared_ptr<ChunkSource> ChunkSourcePtr;
+
+
+
+
+
+class ChunkLoader :
+ public QObject,
+ public QRunnable
+{
+ Q_OBJECT
+
+public:
+ ChunkLoader(int a_ChunkX, int a_ChunkZ, ChunkPtr a_Chunk, ChunkSourcePtr a_ChunkSource);
+ virtual ~ChunkLoader() {}
+
+signals:
+ void loaded(int a_ChunkX, int a_ChunkZ);
+
+protected:
+ virtual void run() override;
+
+private:
+ int m_ChunkX, m_ChunkZ;
+ ChunkPtr m_Chunk;
+ ChunkSourcePtr m_ChunkSource;
+};
+
+
+
+
diff --git a/Tools/QtBiomeVisualiser/ChunkSource.cpp b/Tools/QtBiomeVisualiser/ChunkSource.cpp
new file mode 100644
index 000000000..9e0ea5751
--- /dev/null
+++ b/Tools/QtBiomeVisualiser/ChunkSource.cpp
@@ -0,0 +1,184 @@
+#include "Globals.h"
+#include "ChunkSource.h"
+#include <QThread>
+#include "Generating/BioGen.h"
+#include "inifile/iniFile.h"
+
+
+
+
+
+/** Map for converting biome values to colors. Initialized from biomeColors[]. */
+static uchar biomeToColor[256 * 4];
+
+/** Map for converting biome values to colors. Used to initialize biomeToColor[].*/
+static struct
+{
+ EMCSBiome m_Biome;
+ uchar m_Color[3];
+} biomeColors[] =
+{
+ { biOcean, { 0x00, 0x00, 0x70 }, },
+ { biPlains, { 0x8d, 0xb3, 0x60 }, },
+ { biDesert, { 0xfa, 0x94, 0x18 }, },
+ { biExtremeHills, { 0x60, 0x60, 0x60 }, },
+ { biForest, { 0x05, 0x66, 0x21 }, },
+ { biTaiga, { 0x0b, 0x66, 0x59 }, },
+ { biSwampland, { 0x2f, 0xff, 0xda }, },
+ { biRiver, { 0x30, 0x30, 0xaf }, },
+ { biHell, { 0x7f, 0x00, 0x00 }, },
+ { biSky, { 0x00, 0x7f, 0xff }, },
+ { biFrozenOcean, { 0xa0, 0xa0, 0xdf }, },
+ { biFrozenRiver, { 0xa0, 0xa0, 0xff }, },
+ { biIcePlains, { 0xff, 0xff, 0xff }, },
+ { biIceMountains, { 0xa0, 0xa0, 0xa0 }, },
+ { biMushroomIsland, { 0xff, 0x00, 0xff }, },
+ { biMushroomShore, { 0xa0, 0x00, 0xff }, },
+ { biBeach, { 0xfa, 0xde, 0x55 }, },
+ { biDesertHills, { 0xd2, 0x5f, 0x12 }, },
+ { biForestHills, { 0x22, 0x55, 0x1c }, },
+ { biTaigaHills, { 0x16, 0x39, 0x33 }, },
+ { biExtremeHillsEdge, { 0x7f, 0x8f, 0x7f }, },
+ { biJungle, { 0x53, 0x7b, 0x09 }, },
+ { biJungleHills, { 0x2c, 0x42, 0x05 }, },
+
+ { biJungleEdge, { 0x62, 0x8b, 0x17 }, },
+ { biDeepOcean, { 0x00, 0x00, 0x30 }, },
+ { biStoneBeach, { 0xa2, 0xa2, 0x84 }, },
+ { biColdBeach, { 0xfa, 0xf0, 0xc0 }, },
+ { biBirchForest, { 0x30, 0x74, 0x44 }, },
+ { biBirchForestHills, { 0x1f, 0x5f, 0x32 }, },
+ { biRoofedForest, { 0x40, 0x51, 0x1a }, },
+ { biColdTaiga, { 0x31, 0x55, 0x4a }, },
+ { biColdTaigaHills, { 0x59, 0x7d, 0x72 }, },
+ { biMegaTaiga, { 0x59, 0x66, 0x51 }, },
+ { biMegaTaigaHills, { 0x59, 0x66, 0x59 }, },
+ { biExtremeHillsPlus, { 0x50, 0x70, 0x50 }, },
+ { biSavanna, { 0xbd, 0xb2, 0x5f }, },
+ { biSavannaPlateau, { 0xa7, 0x9d, 0x64 }, },
+ { biMesa, { 0xd9, 0x45, 0x15 }, },
+ { biMesaPlateauF, { 0xb0, 0x97, 0x65 }, },
+ { biMesaPlateau, { 0xca, 0x8c, 0x65 }, },
+
+ // M variants:
+ { biSunflowerPlains, { 0xb5, 0xdb, 0x88 }, },
+ { biDesertM, { 0xff, 0xbc, 0x40 }, },
+ { biExtremeHillsM, { 0x88, 0x88, 0x88 }, },
+ { biFlowerForest, { 0x2d, 0x8e, 0x49 }, },
+ { biTaigaM, { 0x33, 0x8e, 0x81 }, },
+ { biSwamplandM, { 0x07, 0xf9, 0xb2 }, },
+ { biIcePlainsSpikes, { 0xb4, 0xdc, 0xdc }, },
+ { biJungleM, { 0x7b, 0xa3, 0x31 }, },
+ { biJungleEdgeM, { 0x62, 0x8b, 0x17 }, },
+ { biBirchForestM, { 0x58, 0x9c, 0x6c }, },
+ { biBirchForestHillsM, { 0x47, 0x87, 0x5a }, },
+ { biRoofedForestM, { 0x68, 0x79, 0x42 }, },
+ { biColdTaigaM, { 0x24, 0x3f, 0x36 }, },
+ { biMegaSpruceTaiga, { 0x45, 0x4f, 0x3e }, },
+ { biMegaSpruceTaigaHills, { 0x45, 0x4f, 0x4e }, },
+ { biExtremeHillsPlusM, { 0x78, 0x98, 0x78 }, },
+ { biSavannaM, { 0xe5, 0xda, 0x87 }, },
+ { biSavannaPlateauM, { 0xa7, 0x9d, 0x74 }, },
+ { biMesaBryce, { 0xff, 0x6d, 0x3d }, },
+ { biMesaPlateauFM, { 0xd8, 0xbf, 0x8d }, },
+ { biMesaPlateauM, { 0xf2, 0xb4, 0x8d }, },
+} ;
+
+
+
+
+
+static class BiomeColorsInitializer
+{
+public:
+ BiomeColorsInitializer(void)
+ {
+ // Reset all colors to gray:
+ for (size_t i = 0; i < ARRAYCOUNT(biomeToColor); i++)
+ {
+ biomeToColor[i] = 0x7f;
+ }
+
+ // Set known biomes to their colors:
+ for (size_t i = 0; i < ARRAYCOUNT(biomeColors); i++)
+ {
+ uchar * color = &biomeToColor[4 * biomeColors[i].m_Biome];
+ color[0] = biomeColors[i].m_Color[2];
+ color[1] = biomeColors[i].m_Color[1];
+ color[2] = biomeColors[i].m_Color[0];
+ color[3] = 0xff;
+ }
+ }
+} biomeColorInitializer;
+
+
+
+
+
+/** Converts biomes in an array into the chunk image data. */
+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];
+
+ // Convert the biomes into color:
+ for (size_t i = 0; i < ARRAYCOUNT(a_Biomes); i++)
+ {
+ a_Image[4 * i + 0] = biomeToColor[4 * a_Biomes[i] + 0];
+ a_Image[4 * i + 1] = biomeToColor[4 * a_Biomes[i] + 1];
+ a_Image[4 * i + 2] = biomeToColor[4 * a_Biomes[i] + 2];
+ a_Image[4 * i + 3] = biomeToColor[4 * a_Biomes[i] + 3];
+ }
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// BioGenSource:
+
+BioGenSource::BioGenSource(QString a_WorldIniPath) :
+ m_WorldIniPath(a_WorldIniPath),
+ m_Mtx(QMutex::Recursive)
+{
+ reload();
+}
+
+
+
+
+
+void BioGenSource::getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChunk)
+{
+ cChunkDef::BiomeMap biomes;
+ {
+ QMutexLocker lock(&m_Mtx);
+ m_BiomeGen->GenBiomes(a_ChunkX, a_ChunkZ, biomes);
+ }
+ Chunk::Image img;
+ biomesToImage(biomes, img);
+ a_DestChunk->setImage(img);
+}
+
+
+
+
+
+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());
+}
+
+
+
+
diff --git a/Tools/QtBiomeVisualiser/ChunkSource.h b/Tools/QtBiomeVisualiser/ChunkSource.h
new file mode 100644
index 000000000..a485e473a
--- /dev/null
+++ b/Tools/QtBiomeVisualiser/ChunkSource.h
@@ -0,0 +1,75 @@
+#pragma once
+#include <QString>
+#include "Chunk.h"
+
+
+
+
+
+// fwd:
+class cBiomeGen;
+typedef std::shared_ptr<cBiomeGen> cBiomeGenPtr;
+class cIniFile;
+
+
+
+
+
+/** Abstract interface for getting biome data for chunks. */
+class ChunkSource
+{
+public:
+ virtual ~ChunkSource() {}
+
+ /** 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;
+};
+
+
+
+
+
+
+class BioGenSource :
+ public ChunkSource
+{
+public:
+ /** 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:
+ /** 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;
+};
+
+
+
+
+class AnvilSource :
+ public ChunkSource
+{
+public:
+ // TODO
+
+ // ChunkSource overrides:
+ virtual void getChunkBiomes(int a_ChunkX, int a_ChunkZ, ChunkPtr a_DestChunk) override;
+ virtual void reload() override {}
+};
+
+
+
+
diff --git a/Tools/QtBiomeVisualiser/Globals.h b/Tools/QtBiomeVisualiser/Globals.h
new file mode 100644
index 000000000..d3c7f0675
--- /dev/null
+++ b/Tools/QtBiomeVisualiser/Globals.h
@@ -0,0 +1,386 @@
+#pragma once
+
+
+
+
+
+// Compiler-dependent stuff:
+#if defined(_MSC_VER)
+ // MSVC produces warning C4481 on the override keyword usage, so disable the warning altogether
+ #pragma warning(disable:4481)
+
+ // Disable some warnings that we don't care about:
+ #pragma warning(disable:4100) // Unreferenced formal parameter
+
+ // Useful warnings from warning level 4:
+ #pragma warning(3 : 4127) // Conditional expression is constant
+ #pragma warning(3 : 4189) // Local variable is initialized but not referenced
+ #pragma warning(3 : 4245) // Conversion from 'type1' to 'type2', signed/unsigned mismatch
+ #pragma warning(3 : 4310) // Cast truncates constant value
+ #pragma warning(3 : 4389) // Signed/unsigned mismatch
+ #pragma warning(3 : 4505) // Unreferenced local function has been removed
+ #pragma warning(3 : 4701) // Potentially unitialized local variable used
+ #pragma warning(3 : 4702) // Unreachable code
+ #pragma warning(3 : 4706) // Assignment within conditional expression
+
+ // Disabling this warning, because we know what we're doing when we're doing this:
+ #pragma warning(disable: 4355) // 'this' used in initializer list
+
+ // Disabled because it's useless:
+ #pragma warning(disable: 4512) // 'class': assignment operator could not be generated - reported for each class that has a reference-type member
+
+ // 2014_01_06 xoft: Disabled this warning because MSVC is stupid and reports it in obviously wrong places
+ // #pragma warning(3 : 4244) // Conversion from 'type1' to 'type2', possible loss of data
+
+ #define OBSOLETE __declspec(deprecated)
+
+ // No alignment needed in MSVC
+ #define ALIGN_8
+ #define ALIGN_16
+
+ #define FORMATSTRING(formatIndex, va_argsIndex)
+
+ // MSVC has its own custom version of zu format
+ #define SIZE_T_FMT "%Iu"
+ #define SIZE_T_FMT_PRECISION(x) "%" #x "Iu"
+ #define SIZE_T_FMT_HEX "%Ix"
+
+ #define NORETURN __declspec(noreturn)
+
+#elif defined(__GNUC__)
+
+ // TODO: Can GCC explicitly mark classes as abstract (no instances can be created)?
+ #define abstract
+
+ // override is part of c++11
+ #if __cplusplus < 201103L
+ #define override
+ #endif
+
+ #define OBSOLETE __attribute__((deprecated))
+
+ #define ALIGN_8 __attribute__((aligned(8)))
+ #define ALIGN_16 __attribute__((aligned(16)))
+
+ // Some portability macros :)
+ #define stricmp strcasecmp
+
+ #define FORMATSTRING(formatIndex, va_argsIndex) __attribute__((format (printf, formatIndex, va_argsIndex)))
+
+ #if defined(_WIN32)
+ // We're compiling on MinGW, which uses an old MSVCRT library that has no support for size_t printfing.
+ // We need direct size formats:
+ #if defined(_WIN64)
+ #define SIZE_T_FMT "%I64u"
+ #define SIZE_T_FMT_PRECISION(x) "%" #x "I64u"
+ #define SIZE_T_FMT_HEX "%I64x"
+ #else
+ #define SIZE_T_FMT "%u"
+ #define SIZE_T_FMT_PRECISION(x) "%" #x "u"
+ #define SIZE_T_FMT_HEX "%x"
+ #endif
+ #else
+ // We're compiling on Linux, so we can use libc's size_t printf format:
+ #define SIZE_T_FMT "%zu"
+ #define SIZE_T_FMT_PRECISION(x) "%" #x "zu"
+ #define SIZE_T_FMT_HEX "%zx"
+ #endif
+
+ #define NORETURN __attribute((__noreturn__))
+
+#else
+
+ #error "You are using an unsupported compiler, you might need to #define some stuff here for your compiler"
+
+ /*
+ // Copy and uncomment this into another #elif section based on your compiler identification
+
+ // Explicitly mark classes as abstract (no instances can be created)
+ #define abstract
+
+ // Mark virtual methods as overriding (forcing them to have a virtual function of the same signature in the base class)
+ #define override
+
+ // Mark functions as obsolete, so that their usage results in a compile-time warning
+ #define OBSOLETE
+
+ // Mark types / variables for alignment. Do the platforms need it?
+ #define ALIGN_8
+ #define ALIGN_16
+ */
+
+#endif
+
+
+#ifdef _DEBUG
+ #define NORETURNDEBUG NORETURN
+#else
+ #define NORETURNDEBUG
+#endif
+
+
+#include <stddef.h>
+
+
+// Integral types with predefined sizes:
+typedef long long Int64;
+typedef int Int32;
+typedef short Int16;
+
+typedef unsigned long long UInt64;
+typedef unsigned int UInt32;
+typedef unsigned short UInt16;
+
+typedef unsigned char Byte;
+
+
+// If you get an error about specialization check the size of integral types
+template <typename T, size_t Size, bool x = sizeof(T) == Size>
+class SizeChecker;
+
+template <typename T, size_t Size>
+class SizeChecker<T, Size, true>
+{
+ T v;
+};
+
+template class SizeChecker<Int64, 8>;
+template class SizeChecker<Int32, 4>;
+template class SizeChecker<Int16, 2>;
+
+template class SizeChecker<UInt64, 8>;
+template class SizeChecker<UInt32, 4>;
+template class SizeChecker<UInt16, 2>;
+
+// A macro to disallow the copy constructor and operator = functions
+// This should be used in the private: declarations for any class that shouldn't allow copying itself
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+ TypeName(const TypeName &); \
+ void operator =(const TypeName &)
+
+// A macro that is used to mark unused function parameters, to avoid pedantic warnings in gcc
+#define UNUSED(X) (void)(X)
+
+
+
+
+// OS-dependent stuff:
+#ifdef _WIN32
+ #define WIN32_LEAN_AND_MEAN
+
+ #define _WIN32_WINNT 0x501 // We want to target WinXP and higher
+
+ #include <Windows.h>
+ #include <winsock2.h>
+ #include <Ws2tcpip.h> // IPv6 stuff
+
+ // Windows SDK defines min and max macros, messing up with our std::min and std::max usage
+ #undef min
+ #undef max
+
+ // Windows SDK defines GetFreeSpace as a constant, probably a Win16 API remnant
+ #ifdef GetFreeSpace
+ #undef GetFreeSpace
+ #endif // GetFreeSpace
+#else
+ #include <sys/types.h>
+ #include <sys/time.h>
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+ #include <netdb.h>
+ #include <time.h>
+ #include <dirent.h>
+ #include <errno.h>
+ #include <iostream>
+ #include <cstdio>
+ #include <cstring>
+ #include <pthread.h>
+ #include <semaphore.h>
+ #include <errno.h>
+ #include <fcntl.h>
+#endif
+
+#if defined(ANDROID_NDK)
+ #define FILE_IO_PREFIX "/sdcard/mcserver/"
+#else
+ #define FILE_IO_PREFIX ""
+#endif
+
+
+
+
+
+// CRT stuff:
+#include <sys/stat.h>
+#include <assert.h>
+#include <stdio.h>
+#include <math.h>
+#include <stdarg.h>
+
+
+
+
+
+// STL stuff:
+#include <vector>
+#include <list>
+#include <deque>
+#include <string>
+#include <map>
+#include <algorithm>
+#include <memory>
+#include <set>
+#include <queue>
+#include <limits>
+
+
+
+#ifndef TEST_GLOBALS
+ // Common headers (part 1, without macros):
+ #include "StringUtils.h"
+ #include "OSSupport/Sleep.h"
+ #include "OSSupport/CriticalSection.h"
+ #include "OSSupport/Semaphore.h"
+ #include "OSSupport/Event.h"
+ #include "OSSupport/Thread.h"
+ #include "OSSupport/File.h"
+ #include "Logger.h"
+#else
+ // Logging functions
+void inline LOGERROR(const char* a_Format, ...) FORMATSTRING(1, 2);
+
+void inline LOGERROR(const char* a_Format, ...)
+{
+ va_list argList;
+ va_start(argList, a_Format);
+ vprintf(a_Format, argList);
+ va_end(argList);
+}
+#endif
+
+
+
+
+
+// Common definitions:
+
+/// Evaluates to the number of elements in an array (compile-time!)
+#define ARRAYCOUNT(X) (sizeof(X) / sizeof(*(X)))
+
+/// Allows arithmetic expressions like "32 KiB" (but consider using parenthesis around it, "(32 KiB)")
+#define KiB * 1024
+#define MiB * 1024 * 1024
+
+/// Faster than (int)floorf((float)x / (float)div)
+#define FAST_FLOOR_DIV( x, div) (((x) - (((x) < 0) ? ((div) - 1) : 0)) / (div))
+
+// Own version of assert() that writes failed assertions to the log for review
+#ifdef TEST_GLOBALS
+
+ class cAssertFailure
+ {
+ };
+
+ #ifdef _WIN32
+ #if (defined(_MSC_VER) && defined(_DEBUG))
+ #define DBG_BREAK _CrtDbgBreak()
+ #else
+ #define DBG_BREAK
+ #endif
+ #define REPORT_ERROR(FMT, ...) \
+ { \
+ AString msg = Printf(FMT, __VA_ARGS__); \
+ puts(msg.c_str()); \
+ fflush(stdout); \
+ OutputDebugStringA(msg.c_str()); \
+ DBG_BREAK; \
+ }
+ #else
+ #define REPORT_ERROR(FMT, ...) \
+ { \
+ AString msg = Printf(FMT, __VA_ARGS__); \
+ puts(msg.c_str()); \
+ fflush(stdout); \
+ }
+ #endif
+ #define ASSERT(x) do { if (!(x)) { throw cAssertFailure();} } while (0)
+ #define testassert(x) do { if (!(x)) { REPORT_ERROR("Test failure: %s, file %s, line %d\n", #x, __FILE__, __LINE__); exit(1); } } while (0)
+ #define CheckAsserts(x) do { try {x} catch (cAssertFailure) { break; } REPORT_ERROR("Test failure: assert didn't fire for %s, file %s, line %d\n", #x, __FILE__, __LINE__); exit(1); } while (0)
+
+#else
+ #ifdef _DEBUG
+ #define ASSERT( x) ( !!(x) || ( LOGERROR("Assertion failed: %s, file %s, line %i", #x, __FILE__, __LINE__), assert(0), 0))
+ #else
+ #define ASSERT(x) ((void)(x))
+ #endif
+#endif
+
+// Pretty much the same as ASSERT() but stays in Release builds
+#define VERIFY( x) ( !!(x) || ( LOGERROR("Verification failed: %s, file %s, line %i", #x, __FILE__, __LINE__), exit(1), 0))
+
+// Same as assert but in all Self test builds
+#ifdef SELF_TEST
+ #define assert_test(x) ( !!(x) || (assert(!#x), exit(1), 0))
+#endif
+
+// Allow both Older versions of MSVC and newer versions of everything use a shared_ptr:
+// Note that we cannot typedef, because C++ doesn't allow (partial) templates to be typedeffed.
+#if (defined(_MSC_VER) && (_MSC_VER < 1600))
+ // MSVC before 2010 doesn't have std::shared_ptr, but has std::tr1::shared_ptr, defined in <memory> included earlier
+ #define SharedPtr std::tr1::shared_ptr
+#elif (defined(_MSC_VER) || (__cplusplus >= 201103L))
+ // C++11 has std::shared_ptr in <memory>, included earlier
+ #define SharedPtr std::shared_ptr
+#else
+ // C++03 has std::tr1::shared_ptr in <tr1/memory>
+ #include <tr1/memory>
+ #define SharedPtr std::tr1::shared_ptr
+#endif
+
+
+
+
+
+/** A generic interface used mainly in ForEach() functions */
+template <typename Type> class cItemCallback
+{
+public:
+ virtual ~cItemCallback() {}
+
+ /** Called for each item in the internal list; return true to stop the loop, or false to continue enumerating */
+ virtual bool Item(Type * a_Type) = 0;
+} ;
+
+
+
+
+/** Clamp X to the specified range. */
+template <typename T>
+T Clamp(T a_Value, T a_Min, T a_Max)
+{
+ return (a_Value < a_Min) ? a_Min : ((a_Value > a_Max) ? a_Max : a_Value);
+}
+
+
+
+
+
+#ifndef TOLUA_TEMPLATE_BIND
+ #define TOLUA_TEMPLATE_BIND(x)
+#endif
+
+
+
+
+
+// Common headers (part 2, with macros):
+#include "ChunkDef.h"
+#include "BiomeDef.h"
+#include "BlockID.h"
+#include "BlockInfo.h"
+
+
+
+
+
diff --git a/Tools/QtBiomeVisualiser/MainWindow.cpp b/Tools/QtBiomeVisualiser/MainWindow.cpp
new file mode 100644
index 000000000..65d0ccf5e
--- /dev/null
+++ b/Tools/QtBiomeVisualiser/MainWindow.cpp
@@ -0,0 +1,99 @@
+#include "Globals.h"
+#include "MainWindow.h"
+#include <QVBoxLayout>
+#include <QAction>
+#include <QMenuBar>
+#include <QApplication>
+#include <QFileDialog>
+#include "inifile/iniFile.h"
+#include "ChunkSource.h"
+#include "Generating/BioGen.h"
+
+
+
+
+
+MainWindow::MainWindow(QWidget * parent) :
+ QMainWindow(parent)
+{
+ m_BiomeView = new BiomeView(this);
+ setCentralWidget(m_BiomeView);
+
+ createActions();
+ createMenus();
+}
+
+
+
+
+
+MainWindow::~MainWindow()
+{
+
+}
+
+
+
+
+
+void MainWindow::generate()
+{
+ QString worldIni = QFileDialog::getOpenFileName(this, tr("Open world.ini"), QString(), tr("world.ini (world.ini)"));
+ m_BiomeView->setChunkSource(std::shared_ptr<BioGenSource>(new BioGenSource(worldIni)));
+ m_BiomeView->redraw();
+}
+
+
+
+
+
+void MainWindow::open()
+{
+ // TODO
+}
+
+
+
+
+
+void MainWindow::createActions()
+{
+ m_actGen = new QAction(tr("&Generate..."), this);
+ m_actGen->setShortcut(tr("Ctrl+N"));
+ m_actGen->setStatusTip(tr("Open a generator INI file and display the generated biomes"));
+ connect(m_actGen, SIGNAL(triggered()), this, SLOT(generate()));
+
+ m_actOpen = new QAction(tr("&Open world..."), this);
+ m_actOpen->setShortcut(tr("Ctrl+O"));
+ 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()));
+ connect(m_actExit, SIGNAL(triggered()), this, SLOT(close()));
+}
+
+
+
+
+
+void MainWindow::createMenus()
+{
+ QMenu * mFile = menuBar()->addMenu(tr("&World"));
+ mFile->addAction(m_actGen);
+ mFile->addAction(m_actOpen);
+ mFile->addSeparator();
+ mFile->addAction(m_actReload);
+ mFile->addSeparator();
+ mFile->addAction(m_actExit);
+}
+
+
+
+
diff --git a/Tools/QtBiomeVisualiser/MainWindow.h b/Tools/QtBiomeVisualiser/MainWindow.h
new file mode 100644
index 000000000..b37bf4120
--- /dev/null
+++ b/Tools/QtBiomeVisualiser/MainWindow.h
@@ -0,0 +1,47 @@
+#pragma once
+
+#include <QMainWindow>
+#include "BiomeView.h"
+
+
+
+
+
+class MainWindow :
+ public QMainWindow
+{
+ Q_OBJECT
+
+ BiomeView * m_BiomeView;
+
+public:
+ MainWindow(QWidget *parent = 0);
+ ~MainWindow();
+
+private slots:
+ /** Opens a generator definition and generates the biomes based on that. */
+ void generate();
+
+ /** Opens an existing world and displays the loaded biomes. */
+ void open();
+
+protected:
+ // Actions:
+ QAction * m_actGen;
+ QAction * m_actOpen;
+ QAction * m_actReload;
+ QAction * m_actExit;
+
+
+ /** Creates the actions that the UI supports. */
+ void createActions();
+
+ /** Creates the menu bar and connects its events. */
+ void createMenus();
+};
+
+
+
+
+
+
diff --git a/Tools/QtBiomeVisualiser/QtBiomeVisualiser.pro b/Tools/QtBiomeVisualiser/QtBiomeVisualiser.pro
new file mode 100644
index 000000000..0b42f076d
--- /dev/null
+++ b/Tools/QtBiomeVisualiser/QtBiomeVisualiser.pro
@@ -0,0 +1,59 @@
+#-------------------------------------------------
+#
+# Project created by QtCreator 2014-09-11T15:22:43
+#
+#-------------------------------------------------
+
+QT += core gui
+
+greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
+
+TARGET = QtBiomeVisualiser
+TEMPLATE = app
+
+
+SOURCES += main.cpp\
+ MainWindow.cpp \
+ BiomeView.cpp \
+ ../../src/Generating/BioGen.cpp \
+ ../../src/VoronoiMap.cpp \
+ ../../src/Noise.cpp \
+ ../../src/StringUtils.cpp \
+ ../../src/LoggerListeners.cpp \
+ ../../src/Logger.cpp \
+ ../../lib/inifile/iniFile.cpp \
+ ../../src/OSSupport/File.cpp \
+ ../../src/OSSupport/CriticalSection.cpp \
+ ../../src/OSSupport/IsThread.cpp \
+ ../../src/BiomeDef.cpp \
+ ChunkCache.cpp \
+ Chunk.cpp \
+ ChunkSource.cpp \
+ ChunkLoader.cpp
+
+HEADERS += MainWindow.h \
+ Globals.h \
+ BiomeView.h \
+ ../../src/Generating/BioGen.h \
+ ../../src/VoronoiMap.h \
+ ../../src/Noise.h \
+ ../../src/StringUtils.h \
+ ../../src/LoggerListeners.h \
+ ../../src/Logger.h \
+ ../../lib/inifile/iniFile.h \
+ ../../src/OSSupport/File.h \
+ ../../src/OSSupport/CriticalSection.h \
+ ../../src/OSSupport/IsThread.h \
+ ../../src/BiomeDef.h \
+ ChunkCache.h \
+ Chunk.h \
+ ChunkSource.h \
+ ChunkLoader.h
+
+INCLUDEPATH += $$_PRO_FILE_PWD_ \
+ $$_PRO_FILE_PWD_/../../src \
+ $$_PRO_FILE_PWD_/../../lib
+
+
+
+
diff --git a/Tools/QtBiomeVisualiser/main.cpp b/Tools/QtBiomeVisualiser/main.cpp
new file mode 100644
index 000000000..f41cdcfb2
--- /dev/null
+++ b/Tools/QtBiomeVisualiser/main.cpp
@@ -0,0 +1,20 @@
+#include "Globals.h"
+#include "MainWindow.h"
+#include <QApplication>
+
+
+
+
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+ MainWindow w;
+ w.show();
+
+ return a.exec();
+}
+
+
+
+
diff --git a/src/BlockInfo.cpp b/src/BlockInfo.cpp
index 12eeceba2..99bf36d66 100644
--- a/src/BlockInfo.cpp
+++ b/src/BlockInfo.cpp
@@ -548,7 +548,7 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info)
a_Info[E_BLOCK_LOG ].m_PlaceSound = "dig.wood";
a_Info[E_BLOCK_LEAVES ].m_PlaceSound = "dig.grass";
a_Info[E_BLOCK_SPONGE ].m_PlaceSound = "dig.grass";
- a_Info[E_BLOCK_GLASS ].m_PlaceSound = "dig.glass";
+ a_Info[E_BLOCK_GLASS ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_LAPIS_ORE ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_LAPIS_BLOCK ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_DISPENSER ].m_PlaceSound = "dig.stone";
@@ -605,7 +605,7 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info)
a_Info[E_BLOCK_REDSTONE_TORCH_ON ].m_PlaceSound = "dig.wood";
a_Info[E_BLOCK_STONE_BUTTON ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_SNOW ].m_PlaceSound = "dig.snow";
- a_Info[E_BLOCK_ICE ].m_PlaceSound = "dig.glass";
+ a_Info[E_BLOCK_ICE ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_SNOW_BLOCK ].m_PlaceSound = "dig.snow";
a_Info[E_BLOCK_CACTUS ].m_PlaceSound = "dig.cloth";
a_Info[E_BLOCK_CLAY ].m_PlaceSound = "dig.gravel";
@@ -615,20 +615,20 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info)
a_Info[E_BLOCK_PUMPKIN ].m_PlaceSound = "dig.wood";
a_Info[E_BLOCK_NETHERRACK ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_SOULSAND ].m_PlaceSound = "dig.sand";
- a_Info[E_BLOCK_GLOWSTONE ].m_PlaceSound = "dig.glass";
- a_Info[E_BLOCK_NETHER_PORTAL ].m_PlaceSound = "dig.glass";
+ a_Info[E_BLOCK_GLOWSTONE ].m_PlaceSound = "dig.stone";
+ a_Info[E_BLOCK_NETHER_PORTAL ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_JACK_O_LANTERN ].m_PlaceSound = "dig.wood";
a_Info[E_BLOCK_CAKE ].m_PlaceSound = "dig.snow";
a_Info[E_BLOCK_REDSTONE_REPEATER_OFF ].m_PlaceSound = "dig.wood";
a_Info[E_BLOCK_REDSTONE_REPEATER_ON ].m_PlaceSound = "dig.wood";
- a_Info[E_BLOCK_STAINED_GLASS ].m_PlaceSound = "dig.glass";
+ a_Info[E_BLOCK_STAINED_GLASS ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_TRAPDOOR ].m_PlaceSound = "dig.wood";
a_Info[E_BLOCK_SILVERFISH_EGG ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_STONE_BRICKS ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_HUGE_BROWN_MUSHROOM ].m_PlaceSound = "dig.wood";
a_Info[E_BLOCK_HUGE_RED_MUSHROOM ].m_PlaceSound = "dig.wood";
a_Info[E_BLOCK_IRON_BARS ].m_PlaceSound = "dig.metal";
- a_Info[E_BLOCK_GLASS_PANE ].m_PlaceSound = "dig.glass";
+ a_Info[E_BLOCK_GLASS_PANE ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_MELON ].m_PlaceSound = "dig.wood";
a_Info[E_BLOCK_PUMPKIN_STEM ].m_PlaceSound = "dig.wood";
a_Info[E_BLOCK_MELON_STEM ].m_PlaceSound = "dig.wood";
@@ -645,12 +645,12 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info)
a_Info[E_BLOCK_ENCHANTMENT_TABLE ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_BREWING_STAND ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_CAULDRON ].m_PlaceSound = "dig.stone";
- a_Info[E_BLOCK_END_PORTAL ].m_PlaceSound = "dig.glass";
- a_Info[E_BLOCK_END_PORTAL_FRAME ].m_PlaceSound = "dig.glass";
+ a_Info[E_BLOCK_END_PORTAL ].m_PlaceSound = "dig.stone";
+ a_Info[E_BLOCK_END_PORTAL_FRAME ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_END_STONE ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_DRAGON_EGG ].m_PlaceSound = "dig.stone";
- a_Info[E_BLOCK_REDSTONE_LAMP_OFF ].m_PlaceSound = "dig.glass";
- a_Info[E_BLOCK_REDSTONE_LAMP_ON ].m_PlaceSound = "dig.glass";
+ a_Info[E_BLOCK_REDSTONE_LAMP_OFF ].m_PlaceSound = "dig.stone";
+ a_Info[E_BLOCK_REDSTONE_LAMP_ON ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_DOUBLE_WOODEN_SLAB ].m_PlaceSound = "dig.wood";
a_Info[E_BLOCK_WOODEN_SLAB ].m_PlaceSound = "dig.wood";
a_Info[E_BLOCK_COCOA_POD ].m_PlaceSound = "dig.wood";
@@ -670,7 +670,7 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info)
a_Info[E_BLOCK_CARROTS ].m_PlaceSound = "dig.grass";
a_Info[E_BLOCK_POTATOES ].m_PlaceSound = "dig.grass";
a_Info[E_BLOCK_HEAD ].m_PlaceSound = "dig.stone";
- a_Info[E_BLOCK_ANVIL ].m_PlaceSound = "dig.anvil";
+ a_Info[E_BLOCK_ANVIL ].m_PlaceSound = "random.anvil_land";
a_Info[E_BLOCK_TRAPPED_CHEST ].m_PlaceSound = "dig.wood";
a_Info[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE ].m_PlaceSound = "dig.wood";
a_Info[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE ].m_PlaceSound = "dig.wood";
@@ -685,7 +685,7 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info)
a_Info[E_BLOCK_ACTIVATOR_RAIL ].m_PlaceSound = "dig.metal";
a_Info[E_BLOCK_DROPPER ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_STAINED_CLAY ].m_PlaceSound = "dig.stone";
- a_Info[E_BLOCK_STAINED_GLASS_PANE ].m_PlaceSound = "dig.glass";
+ a_Info[E_BLOCK_STAINED_GLASS_PANE ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_NEW_LEAVES ].m_PlaceSound = "dig.grass";
a_Info[E_BLOCK_NEW_LOG ].m_PlaceSound = "dig.wood";
a_Info[E_BLOCK_ACACIA_WOOD_STAIRS ].m_PlaceSound = "dig.wood";
@@ -694,7 +694,7 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info)
a_Info[E_BLOCK_CARPET ].m_PlaceSound = "dig.cloth";
a_Info[E_BLOCK_HARDENED_CLAY ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_BLOCK_OF_COAL ].m_PlaceSound = "dig.stone";
- a_Info[E_BLOCK_PACKED_ICE ].m_PlaceSound = "dig.glass";
+ a_Info[E_BLOCK_PACKED_ICE ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_BIG_FLOWER ].m_PlaceSound = "dig.grass";
}
diff --git a/src/Blocks/BlockBed.cpp b/src/Blocks/BlockBed.cpp
index cd5783f58..cd1cc2a5f 100644
--- a/src/Blocks/BlockBed.cpp
+++ b/src/Blocks/BlockBed.cpp
@@ -15,7 +15,7 @@ void cBlockBedHandler::OnPlacedByPlayer(
if (a_BlockMeta < 8)
{
Vector3i Direction = MetaDataToDirection(a_BlockMeta);
- a_ChunkInterface.SetBlock(a_WorldInterface, a_BlockX + Direction.x, a_BlockY, a_BlockZ + Direction.z, E_BLOCK_BED, a_BlockMeta | 0x8);
+ a_ChunkInterface.SetBlock(a_BlockX + Direction.x, a_BlockY, a_BlockZ + Direction.z, E_BLOCK_BED, a_BlockMeta | 0x8);
}
}
diff --git a/src/Blocks/BlockBigFlower.h b/src/Blocks/BlockBigFlower.h
index 646980634..89ffc864d 100644
--- a/src/Blocks/BlockBigFlower.h
+++ b/src/Blocks/BlockBigFlower.h
@@ -19,16 +19,16 @@ public:
}
- virtual void DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, bool a_CanDrop, bool a_DropVerbatim) override
+ virtual void DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, bool a_CanDrop) override
{
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
if (Meta & 0x8)
{
- super::DropBlock(a_ChunkInterface, a_WorldInterface, a_BlockPluginInterface, a_Digger, a_BlockX, a_BlockY - 1, a_BlockZ, a_CanDrop, a_DropVerbatim);
+ super::DropBlock(a_ChunkInterface, a_WorldInterface, a_BlockPluginInterface, a_Digger, a_BlockX, a_BlockY - 1, a_BlockZ, a_CanDrop);
}
else
{
- super::DropBlock(a_ChunkInterface, a_WorldInterface, a_BlockPluginInterface, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_CanDrop, a_DropVerbatim);
+ super::DropBlock(a_ChunkInterface, a_WorldInterface, a_BlockPluginInterface, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_CanDrop);
}
}
diff --git a/src/Blocks/BlockDoor.cpp b/src/Blocks/BlockDoor.cpp
index 1204debab..1a277f071 100644
--- a/src/Blocks/BlockDoor.cpp
+++ b/src/Blocks/BlockDoor.cpp
@@ -102,7 +102,7 @@ void cBlockDoorHandler::OnPlacedByPlayer(
{
a_TopBlockMeta = 9;
}
- a_ChunkInterface.SetBlock(a_WorldInterface, a_BlockX, a_BlockY + 1, a_BlockZ, m_BlockType, a_TopBlockMeta);
+ a_ChunkInterface.SetBlock(a_BlockX, a_BlockY + 1, a_BlockZ, m_BlockType, a_TopBlockMeta);
}
diff --git a/src/Blocks/BlockFarmland.h b/src/Blocks/BlockFarmland.h
index bb624e54f..02a48a4af 100644
--- a/src/Blocks/BlockFarmland.h
+++ b/src/Blocks/BlockFarmland.h
@@ -28,49 +28,12 @@ public:
virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override
{
- bool Found = false;
-
- EMCSBiome Biome = a_Chunk.GetBiomeAt(a_RelX, a_RelZ);
- if (a_Chunk.GetWorld()->IsWeatherWet() && !IsBiomeNoDownfall(Biome))
- {
- // Rain hydrates farmland, too, except in Desert biomes.
- Found = true;
- }
- else
- {
- // Search for water in a close proximity:
- // Ref.: http://www.minecraftwiki.net/wiki/Farmland#Hydrated_Farmland_Tiles
- // TODO: Rewrite this to use the chunk and its neighbors directly
- cBlockArea Area;
- int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width;
- int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width;
- if (!Area.Read(a_Chunk.GetWorld(), BlockX - 4, BlockX + 4, a_RelY, a_RelY + 1, BlockZ - 4, BlockZ + 4))
- {
- // Too close to the world edge, cannot check surroundings; don't tick at all
- return;
- }
-
- size_t NumBlocks = Area.GetBlockCount();
- BLOCKTYPE * BlockTypes = Area.GetBlockTypes();
- for (size_t i = 0; i < NumBlocks; i++)
- {
- if (IsBlockWater(BlockTypes[i]))
- {
- Found = true;
- break;
- }
- } // for i - BlockTypes[]
- }
-
NIBBLETYPE BlockMeta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ);
-
- if (Found)
+
+ if (IsWaterInNear(a_Chunk, a_RelX, a_RelY, a_RelZ))
{
- // Water was found, hydrate the block until hydration reaches 7:
- if (BlockMeta < 7)
- {
- a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, m_BlockType, ++BlockMeta);
- }
+ // Water was found, set block meta to 7
+ a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, m_BlockType, 7);
return;
}
@@ -80,9 +43,10 @@ public:
a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_FARMLAND, --BlockMeta);
return;
}
-
+
// Farmland too dry. If nothing is growing on top, turn back to dirt:
- switch (a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ))
+ BLOCKTYPE UpperBlock = (a_RelY >= cChunkDef::Height) ? E_BLOCK_AIR : a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ);
+ switch (UpperBlock)
{
case E_BLOCK_CROPS:
case E_BLOCK_POTATOES:
@@ -95,16 +59,63 @@ public:
}
default:
{
- a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_DIRT, 0);
+ a_Chunk.SetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_DIRT, 0);
break;
}
}
}
+ virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override
+ {
+ if (a_BlockY >= cChunkDef::Height)
+ {
+ return;
+ }
+
+ BLOCKTYPE UpperBlock = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ);
+ if (cBlockInfo::FullyOccupiesVoxel(UpperBlock))
+ {
+ a_ChunkInterface.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_DIRT, 0);
+ }
+ }
+
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
a_Pickups.Add(E_BLOCK_DIRT, 1, 0); // Reset meta
}
+
+ bool IsWaterInNear(cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ)
+ {
+ if (a_Chunk.GetWorld()->IsWeatherWetAt(a_RelX, a_RelZ))
+ {
+ // Rain hydrates farmland, too, except in Desert biomes.
+ return true;
+ }
+
+ // Search for water in a close proximity:
+ // Ref.: http://www.minecraftwiki.net/wiki/Farmland#Hydrated_Farmland_Tiles
+ // TODO: Rewrite this to use the chunk and its neighbors directly
+ cBlockArea Area;
+ int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width;
+ int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width;
+ if (!Area.Read(a_Chunk.GetWorld(), BlockX - 4, BlockX + 4, a_RelY, a_RelY + 1, BlockZ - 4, BlockZ + 4))
+ {
+ // Too close to the world edge, cannot check surroundings
+ return false;
+ }
+
+ size_t NumBlocks = Area.GetBlockCount();
+ BLOCKTYPE * BlockTypes = Area.GetBlockTypes();
+ for (size_t i = 0; i < NumBlocks; i++)
+ {
+ if (IsBlockWater(BlockTypes[i]))
+ {
+ return true;
+ }
+ } // for i - BlockTypes[]
+
+ return false;
+ }
} ;
diff --git a/src/Blocks/BlockFenceGate.h b/src/Blocks/BlockFenceGate.h
index ae99a4f94..3041dd46c 100644
--- a/src/Blocks/BlockFenceGate.h
+++ b/src/Blocks/BlockFenceGate.h
@@ -17,6 +17,12 @@ public:
}
+ virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
+ {
+ a_Pickups.Add(E_BLOCK_FENCE_GATE, 1, 0); // Reset meta to zero
+ }
+
+
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface, cPlayer * a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
diff --git a/src/Blocks/BlockFire.h b/src/Blocks/BlockFire.h
index b6d1d95f2..07fcefe16 100644
--- a/src/Blocks/BlockFire.h
+++ b/src/Blocks/BlockFire.h
@@ -126,11 +126,11 @@ public:
{
if (Dir == 1)
{
- a_ChunkInterface.SetBlock(a_WorldInterface, Width, Height, Z, E_BLOCK_NETHER_PORTAL, Dir);
+ a_ChunkInterface.SetBlock(Width, Height, Z, E_BLOCK_NETHER_PORTAL, Dir);
}
else
{
- a_ChunkInterface.SetBlock(a_WorldInterface, X, Height, Width, E_BLOCK_NETHER_PORTAL, Dir);
+ a_ChunkInterface.SetBlock(X, Height, Width, E_BLOCK_NETHER_PORTAL, Dir);
}
}
}
diff --git a/src/Blocks/BlockGravel.h b/src/Blocks/BlockGravel.h
index 717bd5f5f..d076306fb 100644
--- a/src/Blocks/BlockGravel.h
+++ b/src/Blocks/BlockGravel.h
@@ -15,6 +15,19 @@ public:
: cBlockHandler(a_BlockType)
{
}
+
+ virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
+ {
+ cFastRandom Random;
+ if (Random.NextInt(30) == 0)
+ {
+ a_Pickups.Add(E_ITEM_FLINT, 1, 0);
+ }
+ else
+ {
+ a_Pickups.Add(E_BLOCK_GRAVEL, 1, 0);
+ }
+ }
} ;
diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp
index 34925a252..cee2f4b99 100644
--- a/src/Blocks/BlockHandler.cpp
+++ b/src/Blocks/BlockHandler.cpp
@@ -47,6 +47,7 @@
#include "BlockLilypad.h"
#include "BlockLever.h"
#include "BlockMelon.h"
+#include "BlockMobSpawner.h"
#include "BlockMushroom.h"
#include "BlockMycelium.h"
#include "BlockNetherWart.h"
@@ -244,6 +245,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_LOG: return new cBlockSidewaysHandler (a_BlockType);
case E_BLOCK_MELON: return new cBlockMelonHandler (a_BlockType);
case E_BLOCK_MELON_STEM: return new cBlockStemsHandler (a_BlockType);
+ case E_BLOCK_MOB_SPAWNER: return new cBlockMobSpawnerHandler (a_BlockType);
case E_BLOCK_MYCELIUM: return new cBlockMyceliumHandler (a_BlockType);
case E_BLOCK_NETHER_BRICK_STAIRS: return new cBlockStairsHandler (a_BlockType);
case E_BLOCK_NETHER_PORTAL: return new cBlockPortalHandler (a_BlockType);
@@ -417,57 +419,45 @@ void cBlockHandler::ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta)
-void cBlockHandler::DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, bool a_CanDrop, bool a_DropVerbatim)
+void cBlockHandler::DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, bool a_CanDrop)
{
cItems Pickups;
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
if (a_CanDrop)
{
- if (!a_DropVerbatim)
- {
- ConvertToPickups(Pickups, Meta);
- }
- else
- {
- // TODO: Add a proper overridable function for this
- if (a_Digger != NULL)
+ if ((a_Digger != NULL) && (a_Digger->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0))
+ {
+ switch (m_BlockType)
{
- cEnchantments Enchantments = a_Digger->GetEquippedWeapon().m_Enchantments;
- if ((Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0) && a_Digger->IsPlayer())
+ case E_BLOCK_CAKE:
+ case E_BLOCK_CARROTS:
+ case E_BLOCK_COCOA_POD:
+ case E_BLOCK_DOUBLE_STONE_SLAB:
+ case E_BLOCK_DOUBLE_WOODEN_SLAB:
+ case E_BLOCK_FIRE:
+ case E_BLOCK_FARMLAND:
+ case E_BLOCK_MELON_STEM:
+ case E_BLOCK_MOB_SPAWNER:
+ case E_BLOCK_NETHER_WART:
+ case E_BLOCK_POTATOES:
+ case E_BLOCK_PUMPKIN_STEM:
+ case E_BLOCK_SNOW:
+ case E_BLOCK_SUGARCANE:
+ case E_BLOCK_TALL_GRASS:
+ case E_BLOCK_CROPS:
{
- switch (m_BlockType)
- {
- case E_BLOCK_CAKE:
- case E_BLOCK_CARROTS:
- case E_BLOCK_COCOA_POD:
- case E_BLOCK_DOUBLE_STONE_SLAB:
- case E_BLOCK_DOUBLE_WOODEN_SLAB:
- case E_BLOCK_FIRE:
- case E_BLOCK_FARMLAND:
- case E_BLOCK_MELON_STEM:
- case E_BLOCK_MOB_SPAWNER:
- case E_BLOCK_NETHER_WART:
- case E_BLOCK_POTATOES:
- case E_BLOCK_PUMPKIN_STEM:
- case E_BLOCK_SNOW:
- case E_BLOCK_SUGARCANE:
- case E_BLOCK_TALL_GRASS:
- case E_BLOCK_CROPS:
- {
- // Silktouch can't be used for this blocks
- ConvertToPickups(Pickups, Meta);
- break;
- };
- default: Pickups.Add(m_BlockType, 1, Meta);
- }
- }
- else
- {
- Pickups.Add(m_BlockType, 1, Meta);
+ // Silktouch can't be used for these blocks
+ ConvertToPickups(Pickups, Meta);
+ break;
}
+ default: Pickups.Add(m_BlockType, 1, Meta); break;
}
}
+ else
+ {
+ ConvertToPickups(Pickups, Meta);
+ }
}
// Allow plugins to modify the pickups:
diff --git a/src/Blocks/BlockHandler.h b/src/Blocks/BlockHandler.h
index b3ada279c..3a8115da0 100644
--- a/src/Blocks/BlockHandler.h
+++ b/src/Blocks/BlockHandler.h
@@ -82,7 +82,7 @@ public:
@param a_CanDrop Informs the handler whether the block should be dropped at all. One example when this is false is when stone is destroyed by hand
@param a_DropVerbatim Calls ConvertToVerbatimPickups() instead of its counterpart, meaning the block itself is dropped by default (due to a speical tool or enchantment)
*/
- virtual void DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, bool a_CanDrop = true, bool a_DropVerbatim = false);
+ virtual void DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, bool a_CanDrop = true);
/// Checks if the block can stay at the specified relative coords in the chunk
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk);
diff --git a/src/Blocks/BlockMobHead.h b/src/Blocks/BlockMobHead.h
index f19c78694..e21e42334 100644
--- a/src/Blocks/BlockMobHead.h
+++ b/src/Blocks/BlockMobHead.h
@@ -146,9 +146,9 @@ public:
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0);
// Block entities
- a_ChunkInterface.SetBlock(a_WorldInterface, a_BlockX + 1, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
- a_ChunkInterface.SetBlock(a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
- a_ChunkInterface.SetBlock(a_WorldInterface, a_BlockX - 1, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
+ a_ChunkInterface.SetBlock(a_BlockX + 1, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
+ a_ChunkInterface.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
+ a_ChunkInterface.SetBlock(a_BlockX - 1, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
// Spawn the wither:
a_WorldInterface.SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, mtWither);
@@ -176,9 +176,9 @@ public:
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0);
// Block entities
- a_ChunkInterface.SetBlock(a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ + 1, E_BLOCK_AIR, 0);
- a_ChunkInterface.SetBlock(a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
- a_ChunkInterface.SetBlock(a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ - 1, E_BLOCK_AIR, 0);
+ a_ChunkInterface.SetBlock(a_BlockX, a_BlockY, a_BlockZ + 1, E_BLOCK_AIR, 0);
+ a_ChunkInterface.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
+ a_ChunkInterface.SetBlock(a_BlockX, a_BlockY, a_BlockZ - 1, E_BLOCK_AIR, 0);
// Spawn the wither:
a_WorldInterface.SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, mtWither);
diff --git a/src/Blocks/BlockMobSpawner.h b/src/Blocks/BlockMobSpawner.h
new file mode 100644
index 000000000..a51fbaafc
--- /dev/null
+++ b/src/Blocks/BlockMobSpawner.h
@@ -0,0 +1,40 @@
+
+#pragma once
+
+#include "BlockHandler.h"
+#include "../World.h"
+#include "../Items/ItemHandler.h"
+
+
+
+
+
+class cBlockMobSpawnerHandler :
+ public cBlockHandler
+{
+public:
+ cBlockMobSpawnerHandler(BLOCKTYPE a_BlockType)
+ : cBlockHandler(a_BlockType)
+ {
+ }
+
+
+ virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
+ {
+ // No pickups
+ }
+
+
+ virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override
+ {
+ cItemHandler * Handler = a_Player->GetEquippedItem().GetHandler();
+ if (a_Player->IsGameModeCreative() || !Handler->CanHarvestBlock(E_BLOCK_MOB_SPAWNER))
+ {
+ return;
+ }
+
+ cFastRandom Random;
+ int Reward = 15 + Random.NextInt(15) + Random.NextInt(15);
+ a_WorldInterface.SpawnExperienceOrb((double)a_BlockX, (double)a_BlockY + 1, (double)a_BlockZ, Reward);
+ }
+} ;
diff --git a/src/Blocks/BlockOre.h b/src/Blocks/BlockOre.h
index 0067d475f..f6ea3aa3c 100644
--- a/src/Blocks/BlockOre.h
+++ b/src/Blocks/BlockOre.h
@@ -51,7 +51,8 @@ public:
}
default:
{
- ASSERT(!"Unhandled ore!");
+ a_Pickups.push_back(cItem(m_BlockType));
+ break;
}
}
}
diff --git a/src/Blocks/BlockPiston.cpp b/src/Blocks/BlockPiston.cpp
index 164967621..0169fb266 100644
--- a/src/Blocks/BlockPiston.cpp
+++ b/src/Blocks/BlockPiston.cpp
@@ -52,7 +52,7 @@ void cBlockPistonHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorld
if (a_ChunkInterface.GetBlock(newX, newY, newZ) == E_BLOCK_PISTON_EXTENSION)
{
- a_ChunkInterface.SetBlock(a_WorldInterface, newX, newY, newZ, E_BLOCK_AIR, 0);
+ a_ChunkInterface.SetBlock(newX, newY, newZ, E_BLOCK_AIR, 0);
}
}
diff --git a/src/Blocks/ChunkInterface.cpp b/src/Blocks/ChunkInterface.cpp
index 809c24635..a4c96a478 100644
--- a/src/Blocks/ChunkInterface.cpp
+++ b/src/Blocks/ChunkInterface.cpp
@@ -26,9 +26,9 @@ bool cChunkInterface::GetBlockTypeMeta(int a_BlockX, int a_BlockY, int a_BlockZ,
/** Sets the block at the specified coords to the specified value.
Full processing, incl. updating neighbors, is performed.
*/
-void cChunkInterface::SetBlock(cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
+void cChunkInterface::SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
- m_ChunkMap->SetBlock(a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta);
+ m_ChunkMap->SetBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta);
}
void cChunkInterface::SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_MetaData)
diff --git a/src/Blocks/ChunkInterface.h b/src/Blocks/ChunkInterface.h
index dff30a6ee..51647dc04 100644
--- a/src/Blocks/ChunkInterface.h
+++ b/src/Blocks/ChunkInterface.h
@@ -24,7 +24,7 @@ public:
/** Sets the block at the specified coords to the specified value.
Full processing, incl. updating neighbors, is performed.
*/
- void SetBlock(cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
+ void SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
void SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_MetaData);
diff --git a/src/Blocks/WorldInterface.h b/src/Blocks/WorldInterface.h
index 27e06fff3..106c314e7 100644
--- a/src/Blocks/WorldInterface.h
+++ b/src/Blocks/WorldInterface.h
@@ -36,6 +36,9 @@ public:
/** Spawns a mob of the specified type. Returns the mob's EntityID if recognized and spawned, <0 otherwise */
virtual int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType) = 0;
+ /** Spawns an experience orb at the given location with the given reward. It returns the UniqueID of the spawned experience orb. */
+ virtual int SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward) = 0;
+
/** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */
virtual bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback) = 0;
diff --git a/src/Chunk.cpp b/src/Chunk.cpp
index 46520eb56..7f00ee190 100644
--- a/src/Chunk.cpp
+++ b/src/Chunk.cpp
@@ -2215,7 +2215,7 @@ bool cChunk::DoWithRedstonePoweredEntityAt(int a_BlockX, int a_BlockY, int a_Blo
}
}
- if (a_Callback.Item((cRedstonePoweredEntity *)*itr))
+ if (a_Callback.Item(dynamic_cast<cRedstonePoweredEntity *>(*itr))) // Needs dynamic_cast due to multiple inheritance
{
return false;
}
diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp
index 9c105c5af..e8728091f 100644
--- a/src/ChunkMap.cpp
+++ b/src/ChunkMap.cpp
@@ -1287,12 +1287,12 @@ void cChunkMap::SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYP
-void cChunkMap::SetBlock(cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients)
+void cChunkMap::SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients)
{
cChunkInterface ChunkInterface(this);
if (a_BlockType == E_BLOCK_AIR)
{
- BlockHandler(GetBlock(a_BlockX, a_BlockY, a_BlockZ))->OnDestroyed(ChunkInterface, a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ);
+ BlockHandler(GetBlock(a_BlockX, a_BlockY, a_BlockZ))->OnDestroyed(ChunkInterface, *m_World, a_BlockX, a_BlockY, a_BlockZ);
}
int ChunkX, ChunkZ, X = a_BlockX, Y = a_BlockY, Z = a_BlockZ;
@@ -1305,7 +1305,7 @@ void cChunkMap::SetBlock(cWorldInterface & a_WorldInterface, int a_BlockX, int a
Chunk->SetBlock(X, Y, Z, a_BlockType, a_BlockMeta, a_SendToClients);
m_World->GetSimulatorManager()->WakeUp(a_BlockX, a_BlockY, a_BlockZ, Chunk);
}
- BlockHandler(a_BlockType)->OnPlaced(ChunkInterface, a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta);
+ BlockHandler(a_BlockType)->OnPlaced(ChunkInterface, *m_World, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta);
}
diff --git a/src/ChunkMap.h b/src/ChunkMap.h
index 7354536d4..dfa1a57b4 100644
--- a/src/ChunkMap.h
+++ b/src/ChunkMap.h
@@ -151,8 +151,8 @@ public:
NIBBLETYPE GetBlockSkyLight (int a_BlockX, int a_BlockY, int a_BlockZ);
NIBBLETYPE GetBlockBlockLight(int a_BlockX, int a_BlockY, int a_BlockZ);
void SetBlockMeta (int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_BlockMeta);
- void SetBlock (cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients = true);
- void QueueSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Int64 a_Tick, BLOCKTYPE a_PreviousBlockType = E_BLOCK_AIR);
+ void SetBlock (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients = true);
+ void QueueSetBlock (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Int64 a_Tick, BLOCKTYPE a_PreviousBlockType = E_BLOCK_AIR);
bool GetBlockTypeMeta (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta);
bool GetBlockInfo (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight);
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index a6d7c3066..4a3a3c250 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -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();
@@ -1063,7 +1071,7 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc
(m_Player->GetWorld()->GetBlock(a_BlockX, a_BlockY, a_BlockZ) != E_BLOCK_FIRE)
)
{
- // Players can't destroy blocks with a Sword in the hand.
+ // Players can't destroy blocks with a sword in the hand.
return;
}
@@ -1134,6 +1142,12 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo
FinishDigAnimation();
+ if (!m_Player->IsGameModeCreative() && (a_OldBlock == E_BLOCK_BEDROCK))
+ {
+ Kick("You can't break a bedrock!");
+ return;
+ }
+
cWorld * World = m_Player->GetWorld();
cItemHandler * ItemHandler = cItemHandler::GetItemHandler(m_Player->GetEquippedItem());
@@ -1447,8 +1461,20 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e
cChunkInterface ChunkInterface(World->GetChunkMap());
NewBlock->OnPlacedByPlayer(ChunkInterface, *World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta);
- // Step sound with 0.8f pitch is used as block placement sound
- World->BroadcastSoundEffect(cBlockInfo::GetPlaceSound(BlockType), (double)a_BlockX, (double)a_BlockY, (double)a_BlockZ, 1.0f, 0.8f);
+ AString PlaceSound = cBlockInfo::GetPlaceSound(BlockType);
+ float Volume = 1.0f, Pitch = 0.8f;
+ if (PlaceSound == "dig.metal")
+ {
+ Pitch = 1.2f;
+ PlaceSound = "dig.stone";
+ }
+ else if (PlaceSound == "random.anvil_land")
+ {
+ Volume = 0.65f;
+ }
+
+ World->BroadcastSoundEffect(PlaceSound, a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, Volume, Pitch);
+
cRoot::Get()->GetPluginManager()->CallHookPlayerPlacedBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta);
}
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index 74e89deee..3d0995636 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -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.
diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp
index 4581eeda8..398922ef7 100644
--- a/src/Entities/Entity.cpp
+++ b/src/Entities/Entity.cpp
@@ -927,12 +927,13 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
float fallspeed;
if (IsBlockWater(BlockIn))
{
- fallspeed = m_Gravity * a_Dt / 3; // Fall 3x slower in water.
+ fallspeed = m_Gravity * a_Dt / 3; // Fall 3x slower in water
+ ApplyFriction(NextSpeed, 0.7, a_Dt);
}
else if (BlockIn == E_BLOCK_COBWEB)
{
NextSpeed.y *= 0.05; // Reduce overall falling speed
- fallspeed = 0; // No falling.
+ fallspeed = 0; // No falling
}
else
{
@@ -941,20 +942,9 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
}
NextSpeed.y += fallspeed;
}
-
- // Friction
- if (NextSpeed.SqrLength() > 0.0004f)
+ else
{
- NextSpeed.x *= 0.7f / (1 + a_Dt);
- if (fabs(NextSpeed.x) < 0.05)
- {
- NextSpeed.x = 0;
- }
- NextSpeed.z *= 0.7f / (1 + a_Dt);
- if (fabs(NextSpeed.z) < 0.05)
- {
- NextSpeed.z = 0;
- }
+ ApplyFriction(NextSpeed, 0.7, a_Dt);
}
// Adjust X and Z speed for COBWEB temporary. This speed modification should be handled inside block handlers since we
@@ -1060,6 +1050,27 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
+void cEntity::ApplyFriction(Vector3d & a_Speed, double a_SlowdownMultiplier, float a_Dt)
+{
+ if (a_Speed.SqrLength() > 0.0004f)
+ {
+ a_Speed.x *= a_SlowdownMultiplier / (1 + a_Dt);
+ if (fabs(a_Speed.x) < 0.05)
+ {
+ a_Speed.x = 0;
+ }
+ a_Speed.z *= a_SlowdownMultiplier / (1 + a_Dt);
+ if (fabs(a_Speed.z) < 0.05)
+ {
+ a_Speed.z = 0;
+ }
+ }
+}
+
+
+
+
+
void cEntity::TickBurning(cChunk & a_Chunk)
{
// Remember the current burning state:
diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h
index b9c280b6b..6bc070dcc 100644
--- a/src/Entities/Entity.h
+++ b/src/Entities/Entity.h
@@ -535,6 +535,12 @@ protected:
virtual void Destroyed(void) {} // Called after the entity has been destroyed
+ /** Applies friction to an entity
+ @param a_Speed The speed vector to apply changes to
+ @param a_SlowdownMultiplier The factor to reduce the speed by
+ */
+ static void ApplyFriction(Vector3d & a_Speed, double a_SlowdownMultiplier, float a_Dt);
+
/** Called in each tick to handle air-related processing i.e. drowning */
virtual void HandleAir(void);
diff --git a/src/Entities/EntityEffect.cpp b/src/Entities/EntityEffect.cpp
index 8235275a6..d8fa130c0 100644
--- a/src/Entities/EntityEffect.cpp
+++ b/src/Entities/EntityEffect.cpp
@@ -233,6 +233,92 @@ void cEntityEffect::OnTick(cPawn & a_Target)
////////////////////////////////////////////////////////////////////////////////
+// cEntityEffectSpeed:
+
+void cEntityEffectSpeed::OnActivate(cPawn & a_Target)
+{
+ if (a_Target.IsMob())
+ {
+ cMonster * Mob = (cMonster*) &a_Target;
+ Mob->SetRelativeWalkSpeed(Mob->GetRelativeWalkSpeed() + 0.2 * m_Intensity);
+ }
+ else if (a_Target.IsPlayer())
+ {
+ cPlayer * Player = (cPlayer*) &a_Target;
+ Player->SetNormalMaxSpeed(Player->GetNormalMaxSpeed() + 0.2 * m_Intensity);
+ Player->SetSprintingMaxSpeed(Player->GetSprintingMaxSpeed() + 0.26 * m_Intensity);
+ Player->SetFlyingMaxSpeed(Player->GetFlyingMaxSpeed() + 0.2 * m_Intensity);
+ }
+}
+
+
+
+
+
+void cEntityEffectSpeed::OnDeactivate(cPawn & a_Target)
+{
+ if (a_Target.IsMob())
+ {
+ cMonster * Mob = (cMonster*) &a_Target;
+ Mob->SetRelativeWalkSpeed(Mob->GetRelativeWalkSpeed() - 0.2 * m_Intensity);
+ }
+ else if (a_Target.IsPlayer())
+ {
+ cPlayer * Player = (cPlayer*) &a_Target;
+ Player->SetNormalMaxSpeed(Player->GetNormalMaxSpeed() - 0.2 * m_Intensity);
+ Player->SetSprintingMaxSpeed(Player->GetSprintingMaxSpeed() - 0.26 * m_Intensity);
+ Player->SetFlyingMaxSpeed(Player->GetFlyingMaxSpeed() - 0.2 * m_Intensity);
+ }
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// cEntityEffectSlowness:
+
+void cEntityEffectSlowness::OnActivate(cPawn & a_Target)
+{
+ if (a_Target.IsMob())
+ {
+ cMonster * Mob = (cMonster*) &a_Target;
+ Mob->SetRelativeWalkSpeed(Mob->GetRelativeWalkSpeed() - 0.15 * m_Intensity);
+ }
+ else if (a_Target.IsPlayer())
+ {
+ cPlayer * Player = (cPlayer*) &a_Target;
+ Player->SetNormalMaxSpeed(Player->GetNormalMaxSpeed() - 0.15 * m_Intensity);
+ Player->SetSprintingMaxSpeed(Player->GetSprintingMaxSpeed() - 0.195 * m_Intensity);
+ Player->SetFlyingMaxSpeed(Player->GetFlyingMaxSpeed() - 0.15 * m_Intensity);
+ }
+}
+
+
+
+
+
+void cEntityEffectSlowness::OnDeactivate(cPawn & a_Target)
+{
+ if (a_Target.IsMob())
+ {
+ cMonster * Mob = (cMonster*) &a_Target;
+ Mob->SetRelativeWalkSpeed(Mob->GetRelativeWalkSpeed() + 0.15 * m_Intensity);
+ }
+ else if (a_Target.IsPlayer())
+ {
+ cPlayer * Player = (cPlayer*) &a_Target;
+ Player->SetNormalMaxSpeed(Player->GetNormalMaxSpeed() + 0.15 * m_Intensity);
+ Player->SetSprintingMaxSpeed(Player->GetSprintingMaxSpeed() + 0.195 * m_Intensity);
+ Player->SetFlyingMaxSpeed(Player->GetFlyingMaxSpeed() + 0.15 * m_Intensity);
+ }
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
// cEntityEffectInstantHealth:
void cEntityEffectInstantHealth::OnActivate(cPawn & a_Target)
diff --git a/src/Entities/EntityEffect.h b/src/Entities/EntityEffect.h
index 47c298f57..7cf9cd3d5 100644
--- a/src/Entities/EntityEffect.h
+++ b/src/Entities/EntityEffect.h
@@ -137,6 +137,10 @@ public:
super(a_Duration, a_Intensity, a_DistanceModifier)
{
}
+
+ virtual void OnActivate(cPawn & a_Target) override;
+
+ virtual void OnDeactivate(cPawn & a_Target) override;
};
@@ -152,6 +156,10 @@ public:
super(a_Duration, a_Intensity, a_DistanceModifier)
{
}
+
+ virtual void OnActivate(cPawn & a_Target) override;
+
+ virtual void OnDeactivate(cPawn & a_Target) override;
};
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index 4458cd32f..9e373d2c2 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -627,15 +627,6 @@ void cPlayer::FinishEating(void)
return;
}
ItemHandler->OnFoodEaten(m_World, this, &Item);
-
- GetInventory().RemoveOneEquippedItem();
-
- // if the food is mushroom soup, return a bowl to the inventory
- if (Item.m_ItemType == E_ITEM_MUSHROOM_SOUP)
- {
- cItem EmptyBowl(E_ITEM_BOWL);
- GetInventory().AddItem(EmptyBowl, true, true);
- }
}
diff --git a/src/Items/ItemFood.h b/src/Items/ItemFood.h
index 9035344df..1af6e21e8 100644
--- a/src/Items/ItemFood.h
+++ b/src/Items/ItemFood.h
@@ -1,3 +1,4 @@
+
#pragma once
#include "ItemHandler.h"
@@ -39,7 +40,6 @@ public:
// Golden apple handled in ItemGoldenApple
case E_ITEM_GOLDEN_CARROT: return FoodInfo(6, 14.4);
case E_ITEM_MELON_SLICE: return FoodInfo(2, 1.2);
- case E_ITEM_MUSHROOM_SOUP: return FoodInfo(6, 7.2);
case E_ITEM_POISONOUS_POTATO: return FoodInfo(2, 1.2);
// Potatoes handled in ItemSeeds
case E_ITEM_PUMPKIN_PIE: return FoodInfo(8, 4.8);
diff --git a/src/Items/ItemGoldenApple.h b/src/Items/ItemGoldenApple.h
index 02ac0202c..5f6f1de6c 100644
--- a/src/Items/ItemGoldenApple.h
+++ b/src/Items/ItemGoldenApple.h
@@ -36,6 +36,7 @@ public:
a_Player->AddEntityEffect(cEntityEffect::effFireResistance, 6000, 0);
}
+ a_Player->GetInventory().RemoveOneEquippedItem();
return true;
}
diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp
index 67c945ce4..8c3f28c74 100644
--- a/src/Items/ItemHandler.cpp
+++ b/src/Items/ItemHandler.cpp
@@ -33,6 +33,7 @@
#include "ItemLilypad.h"
#include "ItemMap.h"
#include "ItemMinecart.h"
+#include "ItemMushroomSoup.h"
#include "ItemNetherWart.h"
#include "ItemPainting.h"
#include "ItemPickaxe.h"
@@ -125,6 +126,7 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType)
case E_BLOCK_LILY_PAD: return new cItemLilypadHandler(a_ItemType);
case E_ITEM_MAP: return new cItemMapHandler();
case E_ITEM_MILK: return new cItemMilkHandler();
+ case E_ITEM_MUSHROOM_SOUP: return new cItemMushroomSoupHandler(a_ItemType);
case E_ITEM_ITEM_FRAME: return new cItemItemFrameHandler(a_ItemType);
case E_ITEM_NETHER_WART: return new cItemNetherWartHandler(a_ItemType);
case E_ITEM_PAINTING: return new cItemPaintingHandler(a_ItemType);
@@ -216,7 +218,6 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType)
case E_ITEM_COOKIE:
case E_ITEM_GOLDEN_CARROT:
case E_ITEM_MELON_SLICE:
- case E_ITEM_MUSHROOM_SOUP:
case E_ITEM_MUTTON:
case E_ITEM_POISONOUS_POTATO:
case E_ITEM_PUMPKIN_PIE:
@@ -333,7 +334,7 @@ void cItemHandler::OnBlockDestroyed(cWorld * a_World, cPlayer * a_Player, const
{
cChunkInterface ChunkInterface(a_World->GetChunkMap());
cBlockInServerPluginInterface PluginInterface(*a_World);
- Handler->DropBlock(ChunkInterface, *a_World, PluginInterface, a_Player, a_BlockX, a_BlockY, a_BlockZ, CanHarvestBlock(Block), a_Player->GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0);
+ Handler->DropBlock(ChunkInterface, *a_World, PluginInterface, a_Player, a_BlockX, a_BlockY, a_BlockZ, CanHarvestBlock(Block));
}
if (!cBlockInfo::IsOneHitDig(Block))
@@ -582,6 +583,7 @@ bool cItemHandler::CanHarvestBlock(BLOCKTYPE a_BlockType)
case E_BLOCK_SNOW:
case E_BLOCK_VINES:
case E_BLOCK_PACKED_ICE:
+ case E_BLOCK_MOB_SPAWNER:
{
return false;
}
@@ -634,6 +636,10 @@ bool cItemHandler::GetEatEffect(cEntityEffect::eType & a_EffectType, int & a_Eff
bool cItemHandler::EatItem(cPlayer * a_Player, cItem * a_Item)
{
UNUSED(a_Item);
+ if (!a_Player->IsGameModeCreative())
+ {
+ a_Player->GetInventory().RemoveOneEquippedItem();
+ }
FoodInfo Info = GetFoodInfo();
if ((Info.FoodLevel > 0) || (Info.Saturation > 0.f))
diff --git a/src/Items/ItemHoe.h b/src/Items/ItemHoe.h
index 8d0b71478..8e63536d4 100644
--- a/src/Items/ItemHoe.h
+++ b/src/Items/ItemHoe.h
@@ -20,11 +20,17 @@ public:
virtual bool OnItemUse(cWorld *a_World, cPlayer *a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override
{
+ if ((a_Dir == BLOCK_FACE_NONE) || (a_BlockY >= cChunkDef::Height))
+ {
+ return false;
+ }
BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
+ BLOCKTYPE UpperBlock = a_World->GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ);
- if ((Block == E_BLOCK_DIRT) || (Block == E_BLOCK_GRASS))
+ if (((Block == E_BLOCK_DIRT) || (Block == E_BLOCK_GRASS)) && (UpperBlock == E_BLOCK_AIR))
{
a_World->FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_FARMLAND, 0);
+ a_World->BroadcastSoundEffect("dig.gravel", a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, 1.0f, 0.8f);
a_Player->UseEquippedItem();
return true;
}
diff --git a/src/Items/ItemMilk.h b/src/Items/ItemMilk.h
index db7bc13be..c9a90865a 100644
--- a/src/Items/ItemMilk.h
+++ b/src/Items/ItemMilk.h
@@ -21,8 +21,12 @@ public:
{
UNUSED(a_Item);
a_Player->ClearEntityEffects();
- a_Player->GetInventory().RemoveOneEquippedItem();
- a_Player->GetInventory().AddItem(E_ITEM_BUCKET);
+
+ if (!a_Player->IsGameModeCreative())
+ {
+ a_Player->GetInventory().RemoveOneEquippedItem();
+ a_Player->GetInventory().AddItem(E_ITEM_BUCKET);
+ }
return true;
}
};
diff --git a/src/Items/ItemMushroomSoup.h b/src/Items/ItemMushroomSoup.h
new file mode 100644
index 000000000..dba313ec5
--- /dev/null
+++ b/src/Items/ItemMushroomSoup.h
@@ -0,0 +1,53 @@
+
+#pragma once
+
+#include "ItemHandler.h"
+
+
+
+
+
+class cItemMushroomSoupHandler :
+ public cItemHandler
+{
+ typedef cItemHandler super;
+
+public:
+ cItemMushroomSoupHandler(int a_ItemType)
+ : super(a_ItemType)
+ {
+ }
+
+
+ virtual bool IsFood(void) override
+ {
+ return true;
+ }
+
+
+ virtual FoodInfo GetFoodInfo(void) override
+ {
+ return FoodInfo(6, 7.2);
+ }
+
+
+ virtual bool EatItem(cPlayer * a_Player, cItem * a_Item) override
+ {
+ if (!super::EatItem(a_Player, a_Item))
+ {
+ return false;
+ }
+
+ // Return a bowl to the inventory
+ if (!a_Player->IsGameModeCreative())
+ {
+ a_Player->GetInventory().AddItem(cItem(E_ITEM_BOWL), true, true);
+ }
+ return true;
+ }
+
+};
+
+
+
+
diff --git a/src/Items/ItemPickaxe.h b/src/Items/ItemPickaxe.h
index 17fd96822..e0cf5d711 100644
--- a/src/Items/ItemPickaxe.h
+++ b/src/Items/ItemPickaxe.h
@@ -81,6 +81,7 @@ public:
case E_BLOCK_STONE_BRICK_STAIRS:
case E_BLOCK_NETHER_BRICK_STAIRS:
case E_BLOCK_CAULDRON:
+ case E_BLOCK_MOB_SPAWNER:
{
return PickaxeLevel() >= 1;
}
diff --git a/src/Items/ItemPotion.h b/src/Items/ItemPotion.h
index 24614cd8a..398ef6805 100644
--- a/src/Items/ItemPotion.h
+++ b/src/Items/ItemPotion.h
@@ -68,8 +68,12 @@ public:
cEntityEffect::GetPotionEffectDuration(PotionDamage),
cEntityEffect::GetPotionEffectIntensity(PotionDamage)
);
- a_Player->GetInventory().RemoveOneEquippedItem();
- a_Player->GetInventory().AddItem(E_ITEM_GLASS_BOTTLE);
+
+ if (!a_Player->IsGameModeCreative())
+ {
+ a_Player->GetInventory().RemoveOneEquippedItem();
+ a_Player->GetInventory().AddItem(E_ITEM_GLASS_BOTTLE);
+ }
return true;
}
};
diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp
index b6e22c0ee..8c93fea2a 100644
--- a/src/Mobs/Monster.cpp
+++ b/src/Mobs/Monster.cpp
@@ -89,6 +89,7 @@ cMonster::cMonster(const AString & a_ConfigName, eMonsterType a_MobType, const A
, m_DropChanceBoots(0.085f)
, m_CanPickUpLoot(true)
, m_BurnsInDaylight(false)
+ , m_RelativeWalkSpeed(1.0)
{
if (!a_ConfigName.empty())
{
@@ -282,7 +283,7 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk)
}
}
- Vector3f Distance = m_Destination - GetPosition();
+ Vector3d Distance = m_Destination - GetPosition();
if (!ReachedDestination() && !ReachedFinalDestination()) // If we haven't reached any sort of destination, move
{
Distance.y = 0;
@@ -302,6 +303,9 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk)
Distance *= 0.25f;
}
+ // Apply walk speed:
+ Distance *= m_RelativeWalkSpeed;
+
AddSpeedX(Distance.x);
AddSpeedZ(Distance.z);
diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h
index 60bf36c7a..ef94262f6 100644
--- a/src/Mobs/Monster.h
+++ b/src/Mobs/Monster.h
@@ -102,6 +102,9 @@ public:
/// Sets whether the mob burns in daylight. Only evaluated at next burn-decision tick
void SetBurnsInDaylight(bool a_BurnsInDaylight) { m_BurnsInDaylight = a_BurnsInDaylight; }
+ double GetRelativeWalkSpeed(void) const { return m_RelativeWalkSpeed; } // tolua_export
+ void SetRelativeWalkSpeed(double a_WalkSpeed) { m_RelativeWalkSpeed = a_WalkSpeed; } // tolua_export
+
// Overridables to handle ageable mobs
virtual bool IsBaby (void) const { return false; }
virtual bool IsTame (void) const { return false; }
@@ -212,6 +215,8 @@ protected:
void HandleDaylightBurning(cChunk & a_Chunk);
bool m_BurnsInDaylight;
+ double m_RelativeWalkSpeed;
+
/** Adds a random number of a_Item between a_Min and a_Max to itemdrops a_Drops*/
void AddRandomDropItem(cItems & a_Drops, unsigned int a_Min, unsigned int a_Max, short a_Item, short a_ItemHealth = 0);
diff --git a/src/OSSupport/File.cpp b/src/OSSupport/File.cpp
index 2194c46ee..cb6031da6 100644
--- a/src/OSSupport/File.cpp
+++ b/src/OSSupport/File.cpp
@@ -298,7 +298,7 @@ bool cFile::Rename(const AString & a_OrigFileName, const AString & a_NewFileName
bool cFile::Copy(const AString & a_SrcFileName, const AString & a_DstFileName)
{
#ifdef _WIN32
- return (CopyFile(a_SrcFileName.c_str(), a_DstFileName.c_str(), true) != 0);
+ return (CopyFileA(a_SrcFileName.c_str(), a_DstFileName.c_str(), true) != 0);
#else
// Other OSs don't have a direct CopyFile equivalent, do it the harder way:
std::ifstream src(a_SrcFileName.c_str(), std::ios::binary);
@@ -322,7 +322,7 @@ bool cFile::Copy(const AString & a_SrcFileName, const AString & a_DstFileName)
bool cFile::IsFolder(const AString & a_Path)
{
#ifdef _WIN32
- DWORD FileAttrib = GetFileAttributes(a_Path.c_str());
+ DWORD FileAttrib = GetFileAttributesA(a_Path.c_str());
return ((FileAttrib != INVALID_FILE_ATTRIBUTES) && ((FileAttrib & FILE_ATTRIBUTE_DIRECTORY) != 0));
#else
struct stat st;
@@ -337,7 +337,7 @@ bool cFile::IsFolder(const AString & a_Path)
bool cFile::IsFile(const AString & a_Path)
{
#ifdef _WIN32
- DWORD FileAttrib = GetFileAttributes(a_Path.c_str());
+ DWORD FileAttrib = GetFileAttributesA(a_Path.c_str());
return ((FileAttrib != INVALID_FILE_ATTRIBUTES) && ((FileAttrib & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE)) == 0));
#else
struct stat st;
@@ -366,7 +366,7 @@ int cFile::GetSize(const AString & a_FileName)
bool cFile::CreateFolder(const AString & a_FolderPath)
{
#ifdef _WIN32
- return (CreateDirectory(a_FolderPath.c_str(), NULL) != 0);
+ return (CreateDirectoryA(a_FolderPath.c_str(), NULL) != 0);
#else
return (mkdir(a_FolderPath.c_str(), S_IRWXU | S_IRWXG | S_IRWXO) == 0);
#endif
@@ -396,13 +396,13 @@ AStringVector cFile::GetFolderContents(const AString & a_Folder)
// Find all files / folders:
FileFilter.append("*.*");
HANDLE hFind;
- WIN32_FIND_DATA FindFileData;
- if ((hFind = FindFirstFile(FileFilter.c_str(), &FindFileData)) != INVALID_HANDLE_VALUE)
+ WIN32_FIND_DATAA FindFileData;
+ if ((hFind = FindFirstFileA(FileFilter.c_str(), &FindFileData)) != INVALID_HANDLE_VALUE)
{
do
{
AllFiles.push_back(FindFileData.cFileName);
- } while (FindNextFile(hFind, &FindFileData));
+ } while (FindNextFileA(hFind, &FindFileData));
FindClose(hFind);
}
diff --git a/src/OSSupport/IsThread.h b/src/OSSupport/IsThread.h
index c20fc3e7e..5de5f31c4 100644
--- a/src/OSSupport/IsThread.h
+++ b/src/OSSupport/IsThread.h
@@ -69,7 +69,7 @@ protected:
static DWORD __stdcall thrExecute(LPVOID a_Param)
{
// Create a window so that the thread can be identified by 3rd party tools:
- HWND IdentificationWnd = CreateWindow("STATIC", ((cIsThread *)a_Param)->m_ThreadName.c_str(), 0, 0, 0, 0, WS_OVERLAPPED, NULL, NULL, NULL, NULL);
+ HWND IdentificationWnd = CreateWindowA("STATIC", ((cIsThread *)a_Param)->m_ThreadName.c_str(), 0, 0, 0, 0, WS_OVERLAPPED, NULL, NULL, NULL, NULL);
// Run the thread:
((cIsThread *)a_Param)->Execute();
diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp
index ac7a180d4..3b8800867 100644
--- a/src/Protocol/Protocol17x.cpp
+++ b/src/Protocol/Protocol17x.cpp
@@ -100,6 +100,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 (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)
{
@@ -1033,9 +1046,9 @@ void cProtocol172::SendExperienceOrb(const cExpOrb & a_ExpOrb)
cPacketizer Pkt(*this, 0x11);
Pkt.WriteVarInt(a_ExpOrb.GetUniqueID());
- Pkt.WriteInt((int) a_ExpOrb.GetPosX());
- Pkt.WriteInt((int) a_ExpOrb.GetPosY());
- Pkt.WriteInt((int) a_ExpOrb.GetPosZ());
+ Pkt.WriteFPInt(a_ExpOrb.GetPosX());
+ Pkt.WriteFPInt(a_ExpOrb.GetPosY());
+ Pkt.WriteFPInt(a_ExpOrb.GetPosZ());
Pkt.WriteShort(a_ExpOrb.GetReward());
}
diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp
index 8b395230a..d836291c3 100644
--- a/src/Protocol/ProtocolRecognizer.cpp
+++ b/src/Protocol/ProtocolRecognizer.cpp
@@ -27,7 +27,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
{
}
diff --git a/src/StringUtils.cpp b/src/StringUtils.cpp
index 5f88cbf64..73147eebc 100644
--- a/src/StringUtils.cpp
+++ b/src/StringUtils.cpp
@@ -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;
+}
+
+
+
+
diff --git a/src/StringUtils.h b/src/StringUtils.h
index 72a90a8c2..a76894d05 100644
--- a/src/StringUtils.h
+++ b/src/StringUtils.h
@@ -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)
diff --git a/src/VoronoiMap.cpp b/src/VoronoiMap.cpp
index 5efd09c01..68147ebfc 100644
--- a/src/VoronoiMap.cpp
+++ b/src/VoronoiMap.cpp
@@ -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);
}
@@ -111,12 +135,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;
diff --git a/src/VoronoiMap.h b/src/VoronoiMap.h
index 84cf206e9..49f6c1da1 100644
--- a/src/VoronoiMap.h
+++ b/src/VoronoiMap.h
@@ -18,18 +18,28 @@
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
+ /** 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);
protected:
@@ -38,8 +48,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;
diff --git a/src/World.cpp b/src/World.cpp
index 43f7faf94..1de158b5f 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -1727,7 +1727,7 @@ bool cWorld::SetAreaBiome(const cCuboid & a_Area, EMCSBiome a_Biome)
void cWorld::SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients)
{
- m_ChunkMap->SetBlock(*this, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_SendToClients);
+ m_ChunkMap->SetBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_SendToClients);
}
diff --git a/src/World.h b/src/World.h
index 44bf13b03..b07e90818 100644
--- a/src/World.h
+++ b/src/World.h
@@ -470,7 +470,7 @@ public:
int SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType, const cItem & a_Content = cItem(), int a_BlockHeight = 1);
/** Spawns an experience orb at the given location with the given reward. It returns the UniqueID of the spawned experience orb. */
- int SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward);
+ virtual int SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward) override;
/** Spawns a new primed TNT entity at the specified block coords and specified fuse duration. Initial velocity is given based on the relative coefficient provided */
void SpawnPrimedTNT(double a_X, double a_Y, double a_Z, int a_FuseTimeInSec = 80, double a_InitialVelocityCoeff = 1);