Merge branch 'master' into cmake-win
commit
90213d324a
|
@ -8,6 +8,7 @@
|
||||||
<script src="lang-lua.js"></script>
|
<script src="lang-lua.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<div id="content">
|
||||||
<h1>Webserver vs World threads</h1>
|
<h1>Webserver vs World threads</h1>
|
||||||
<p>
|
<p>
|
||||||
This article will explain the threading issues that arise between the webserver and world threads are of concern to plugin authors.</p>
|
This article will explain the threading issues that arise between the webserver and world threads are of concern to plugin authors.</p>
|
||||||
|
@ -65,5 +66,6 @@
|
||||||
<script>
|
<script>
|
||||||
prettyPrint();
|
prettyPrint();
|
||||||
</script>
|
</script>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -0,0 +1,253 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<!--MCServer, a divison of McDonalds Enterprises-->
|
||||||
|
<title>MCS Plugin Tutorial</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="main.css" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="prettify.css" />
|
||||||
|
<script src="prettify.js"></script>
|
||||||
|
<script src="lang-lua.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="content">
|
||||||
|
<h1>Writing a MCServer plugin</h1>
|
||||||
|
<p>
|
||||||
|
This article will explain how to write a basic plugin. It details basic requirements
|
||||||
|
for a plugin, explains how to register a hook and bind a command, and gives plugin
|
||||||
|
standards details.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Let us begin. In order to begin development, we must firstly obtain a compiled copy
|
||||||
|
of MCServer, and make sure that the Core plugin is within the Plugins folder, and activated.
|
||||||
|
Core handles much of the MCServer end-user experience and is a necessary component of
|
||||||
|
plugin development, as necessary plugin components depend on sone of its functions.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Next, we must obtain a copy of CoreMessaging.lua. This can be found
|
||||||
|
<a href="https://raw.github.com/mc-server/MCServer/master/MCServer/Plugins/MagicCarpet/coremessaging.lua">here.</a>
|
||||||
|
This is used to provide messaging support that is compliant with MCServer standards.
|
||||||
|
</p>
|
||||||
|
<h2>Creating the basic template</h2>
|
||||||
|
<p>
|
||||||
|
Plugins are written in Lua. Therefore, create a new Lua file. You can create as many files as you wish, with
|
||||||
|
any filename - MCServer bungs them all together at runtime, however, let us create a file called main.lua for now.
|
||||||
|
Format it like so:
|
||||||
|
</p>
|
||||||
|
<pre class="prettyprint lang-lua">
|
||||||
|
local PLUGIN
|
||||||
|
|
||||||
|
function Initialize( Plugin )
|
||||||
|
Plugin:SetName( "DerpyPlugin" )
|
||||||
|
Plugin:SetVersion( 1 )
|
||||||
|
|
||||||
|
PLUGIN = Plugin
|
||||||
|
|
||||||
|
-- Hooks
|
||||||
|
|
||||||
|
local PluginManager = cPluginManager:Get()
|
||||||
|
-- Command bindings
|
||||||
|
|
||||||
|
LOG( "Initialised " .. Plugin:GetName() .. " v." .. Plugin:GetVersion() )
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function OnDisable()
|
||||||
|
LOG(PLUGIN:GetName() .. " is shutting down...")
|
||||||
|
end
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
Now for an explanation of the basics.
|
||||||
|
<ul>
|
||||||
|
<li><b>function Initialize</b> is called on plugin startup. It is the place where the plugin is set up.</li>
|
||||||
|
<li><b>Plugin:SetName</b> sets the name of the plugin.</li>
|
||||||
|
<li><b>Plugin:SetVersion</b> sets the revision number of the plugin. This must be an integer.</li>
|
||||||
|
<li><b>LOG</b> logs to console a message, in this case, it prints that the plugin was initialised.</li>
|
||||||
|
<li>The <b>PLUGIN</b> variable just stores this plugin's object, so GetName() can be called in OnDisable (as no Plugin parameter is passed there, contrary to Initialize).</li>
|
||||||
|
<li><b>function OnDisable</b> is called when the plugin is disabled, commonly when the server is shutting down. Perform cleanup and logging here.</li>
|
||||||
|
</ul>
|
||||||
|
Be sure to return true for this function, else MCS thinks you plugin had failed to initialise and prints a stacktrace with an error message.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Registering hooks</h2>
|
||||||
|
<p>
|
||||||
|
Hooks are things that MCServer calls when an internal event occurs. For example, a hook is fired when a player places a block, moves,
|
||||||
|
logs on, eats, and many other things. For a full list, see <a href="http://mc-server.xoft.cz/LuaAPI/">the API documentation</a>.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
A hook can be either informative or overridable. In any case, returning false will not trigger a response, but returning true will cancel
|
||||||
|
the hook and prevent it from being propagated further to other plugins. An overridable hook simply means that there is visible behaviour
|
||||||
|
to a hook's cancellation, such as a chest being prevented from being opened. There are some exceptions to this where only changing the value the
|
||||||
|
hook passes has an effect, and not the actual return value, an example being the HOOK_KILLING hook. See the API docs for details.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
To register a hook, insert the following code template into the "-- Hooks" area in the previous code example.
|
||||||
|
</p>
|
||||||
|
<pre class="prettyprint lang-lua">
|
||||||
|
cPluginManager.AddHook(cPluginManager.HOOK_NAME_HERE, FunctionNameToBeCalled)
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
What does this code do?
|
||||||
|
<ul>
|
||||||
|
<li><b>cPluginManager.AddHook</b> registers the hook. The hook name is the second parameter. See the previous API documentation link for a list of all hooks.</li>
|
||||||
|
</ul>
|
||||||
|
What about the third parameter, you ask? Well, it is the name of the function that MCServer calls when the hook fires. It is in this
|
||||||
|
function that you should handle or cancel the hook.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
So in total, this is a working representation of what we have so far covered.
|
||||||
|
</p>
|
||||||
|
<pre class="prettyprint lang-lua">
|
||||||
|
function Initialize( Plugin )
|
||||||
|
Plugin:SetName( "DerpyPlugin" )
|
||||||
|
Plugin:SetVersion( 1 )
|
||||||
|
|
||||||
|
cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_MOVING, OnPlayerMoving)
|
||||||
|
|
||||||
|
local PluginManager = cPluginManager:Get()
|
||||||
|
-- Command bindings
|
||||||
|
|
||||||
|
LOG( "Initialised " .. Plugin:GetName() .. " v." .. Plugin:GetVersion() )
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function OnPlayerMoving(Player) -- See API docs for parameters of all hooks
|
||||||
|
return true -- Prohibit player movement, see docs for whether a hook is cancellable
|
||||||
|
end
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
So, that code stops the player from moving. Not particularly helpful, but yes :P. Note that ALL documentation is available
|
||||||
|
on the main API docs page, so if ever in doubt, go there.
|
||||||
|
</p>
|
||||||
|
<h2>Binding a command</h2>
|
||||||
|
<h3>Format</h3>
|
||||||
|
<p>
|
||||||
|
So now we know how to hook into MCServer, how do we bind a command, such as /explode, for a player to type? That is more complicated.
|
||||||
|
We firstly add this template to the "-- Command bindings" section of the initial example:
|
||||||
|
</p>
|
||||||
|
<pre class="prettyprint lang-lua">
|
||||||
|
-- ADD THIS IF COMMAND DOES NOT REQUIRE A PARAMETER (/explode)
|
||||||
|
PluginManager:BindCommand("/commandname", "permissionnode", FunctionToCall, " - Description of command")
|
||||||
|
|
||||||
|
-- ADD THIS IF COMMAND DOES REQUIRE A PARAMETER (/explode Notch)
|
||||||
|
PluginManager:BindCommand("/commandname", "permissionnode", FunctionToCall, " ~ Description of command and parameter(s)")
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
What does it do, and why are there two?
|
||||||
|
<ul>
|
||||||
|
<li><b>PluginManager:BindCommand</b> binds a command. It takes the command name (with a slash), the permission a player needs to execute the command, the function
|
||||||
|
to call when the command is executed, and a description of the command.</li>
|
||||||
|
</ul>
|
||||||
|
The command name is pretty self explanatory. The permission node is basically just a <b>string</b> that the player's group needs to have, so you can have anything in there,
|
||||||
|
though we recommend a style such as "derpyplugin.explode". The function to call is like the ones with Hooks, but with some fixed parameters which we will come on to later,
|
||||||
|
and the description is a description of the command which is shown when "/help" is typed.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
So why are there two? Standards. A plugin that accepts a parameter MUST use a format for the description of " ~ Description of command and parms"
|
||||||
|
whereas a command that doesn't accept parameters MUST use " - Description of command" instead. Be sure to put a space before the tildes or dashes.
|
||||||
|
Additionally, try to keep the description brief and on one line on the client.
|
||||||
|
</p>
|
||||||
|
<h3>Parameters</h3>
|
||||||
|
<p>
|
||||||
|
What parameters are in the function MCServer calls when the command is executed? A 'Split' array and a 'Player' object.
|
||||||
|
</p>
|
||||||
|
<h4>The Split Array</h4>
|
||||||
|
<p>
|
||||||
|
The Split array is an array of all text submitted to the server, including the actual command. MCServer automatically splits the text into the array,
|
||||||
|
so plugin authors do not need to worry about that. An example of a Split array passed for the command, "/derp zubby explode" would be:<br /><br />
|
||||||
|
   /derp (Split[1])<br />
|
||||||
|
   zubby (Split[2])<br />
|
||||||
|
   explode (Split[3])<br />
|
||||||
|
<br />
|
||||||
|
   The total amount of parameters passed were: 3 (#Split)
|
||||||
|
</p>
|
||||||
|
<h4>The Player Object and sending them messages</h4>
|
||||||
|
<p>
|
||||||
|
The Player object is basically a pointer to the player that has executed the command. You can do things with them, but most common is sending
|
||||||
|
a message. Again, see the API documentation for fuller details. But, you ask, how <i>do</i> we send a message to the client?
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Remember that copy of CoreMessaging.lua that we downloaded earlier? Make sure that file is in your plugin folder, along with the main.lua file you are typing
|
||||||
|
your code in. Since MCS brings all the files together on JIT compile, we don't need to worry about requiring any files or such. Simply follow the below examples:
|
||||||
|
</p>
|
||||||
|
<pre class="prettyprint lang-lua">
|
||||||
|
-- Format: §yellow[INFO] §white%text% (yellow [INFO], white text following it)
|
||||||
|
-- Use: Informational message, such as instructions for usage of a command
|
||||||
|
SendMessage(Player, "Usage: /explode [player]")
|
||||||
|
|
||||||
|
-- Format: §green[INFO] §white%text% (green [INFO] etc.)
|
||||||
|
-- Use: Success message, like when a command executes successfully
|
||||||
|
SendMessageSuccess(Player, "Notch was blown up!")
|
||||||
|
|
||||||
|
-- Format: §rose[INFO] §white%text% (rose coloured [INFO] etc.)
|
||||||
|
-- Use: Failure message, like when a command was entered correctly but failed to run, such as when the destination player wasn't found in a /tp command
|
||||||
|
SendMessageFailure(Player, "Player Salted was not found")
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
Those are the basics. If you want to output text to the player for a reason other than the three listed above, and you want to colour the text, simply concatenate
|
||||||
|
"cChatColor.*colorhere*" with your desired text, concatenate being "..". See the API docs for more details of all colours, as well as details on logging to console with
|
||||||
|
LOG("Text").
|
||||||
|
</p>
|
||||||
|
<h2>Final example and conclusion</h2>
|
||||||
|
<p>
|
||||||
|
So, a working example that checks the validity of a command, and blows up a player, and also refuses pickup collection to players with >100ms ping.
|
||||||
|
</p>
|
||||||
|
<pre class="prettyprint lang-lua">
|
||||||
|
function Initialize( Plugin )
|
||||||
|
Plugin:SetName( "DerpyPluginThatBlowsPeopleUp" )
|
||||||
|
Plugin:SetVersion( 9001 )
|
||||||
|
|
||||||
|
local PluginManager = cPluginManager:Get()
|
||||||
|
PluginManager:BindCommand("/explode", "derpyplugin.explode", Explode, " ~ Explode a player");
|
||||||
|
|
||||||
|
cPluginManager.AddHook(cPluginManager.HOOK_COLLECTING_PICKUP, OnCollectingPickup)
|
||||||
|
|
||||||
|
LOG( "Initialised " .. Plugin:GetName() .. " v." .. Plugin:GetVersion() )
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function Explode(Split, Player)
|
||||||
|
if #Split ~= 2
|
||||||
|
SendMessage(Player, "Usage: /explode [playername]") -- There was more or less than one argument (excluding the /explode bit)
|
||||||
|
else
|
||||||
|
local ExplodePlayer = function(Explodee) -- Create a callback ExplodePlayer with parameter Explodee, which MCS calls for every player on the server
|
||||||
|
if (Explodee:GetName() == Split[2] then -- If the player we are currently at is the one we specified as the parameter...
|
||||||
|
Player:GetWorld():DoExplosionAt(Explodee:GetPosX(), Explodee:GetPosY(), Explodee:GetPosZ(), false, esPlugin) -- Explode 'em; see API docs for further details of this function
|
||||||
|
SendMessageSuccess(Player, Split[2] .. " was successfully exploded") -- Success!
|
||||||
|
return true -- Break out
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
cRoot:Get():FindAndDoWithPlayer(Split[2], ExplodePlayer) -- Tells MCS to loop through all players and call the callback above with the Player object it has found
|
||||||
|
|
||||||
|
SendMessageFailure(Player, Split[2] .. " was not found") -- We have not broken out so far, therefore, the player must not exist, send failure
|
||||||
|
end
|
||||||
|
|
||||||
|
return true -- Concluding return
|
||||||
|
end
|
||||||
|
|
||||||
|
function OnCollectingPickup(Player, Pickup) -- Again, see the API docs for parameters of all hooks. In this case, it is a Player and Pickup object
|
||||||
|
if (Player:GetClientHandle():GetPing() > 100) then -- Get ping of player, in milliseconds
|
||||||
|
return true -- Discriminate against high latency - you don't get drops :D
|
||||||
|
else
|
||||||
|
return false -- You do get the drops! Yay~
|
||||||
|
end
|
||||||
|
end
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
Make sure to read the comments for a description of what everything does. Also be sure to return true for all <b>command</b> handlers, unless you want MCS to print out an "Unknown command" message
|
||||||
|
when the command gets executed :P. Make sure to follow standards - use CoreMessaging.lua functions for messaging, dashes for no parameter commands and tildes for vice versa,
|
||||||
|
and finally, <a href="http://mc-server.xoft.cz/LuaAPI/">the API documentation</a> is your friend!
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Happy coding ;)
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
prettyPrint();
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
<footer>This tutorial was brought you by Aperture Science, in conjunction with McDonalds Enterprises.<br /></footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -49,6 +49,12 @@ header
|
||||||
font-family: Segoe UI Light, Helvetica;
|
font-family: Segoe UI Light, Helvetica;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
footer
|
||||||
|
{
|
||||||
|
text-align: center;
|
||||||
|
font-family: Segoe UI Light, Helvetica;
|
||||||
|
}
|
||||||
|
|
||||||
#content
|
#content
|
||||||
{
|
{
|
||||||
padding: 0px 25px 25px 25px;
|
padding: 0px 25px 25px 25px;
|
||||||
|
|
|
@ -820,6 +820,22 @@ void cPlayer::KilledBy(cEntity * a_Killer)
|
||||||
m_Inventory.Clear();
|
m_Inventory.Clear();
|
||||||
m_World->SpawnItemPickups(Pickups, GetPosX(), GetPosY(), GetPosZ(), 10);
|
m_World->SpawnItemPickups(Pickups, GetPosX(), GetPosY(), GetPosZ(), 10);
|
||||||
SaveToDisk(); // Save it, yeah the world is a tough place !
|
SaveToDisk(); // Save it, yeah the world is a tough place !
|
||||||
|
|
||||||
|
if (a_Killer == NULL)
|
||||||
|
{
|
||||||
|
GetWorld()->BroadcastChat(Printf("%s[DEATH] %s%s was killed by environmental damage", cChatColor::Red.c_str(), cChatColor::White.c_str(), GetName().c_str()));
|
||||||
|
}
|
||||||
|
else if (a_Killer->IsPlayer())
|
||||||
|
{
|
||||||
|
GetWorld()->BroadcastChat(Printf("%s[DEATH] %s%s was killed by %s", cChatColor::Red.c_str(), cChatColor::White.c_str(), GetName().c_str(), ((cPlayer *)a_Killer)->GetName().c_str()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AString KillerClass = a_Killer->GetClass();
|
||||||
|
KillerClass.erase(KillerClass.begin()); // Erase the 'c' of the class (e.g. "cWitch" -> "Witch")
|
||||||
|
|
||||||
|
GetWorld()->BroadcastChat(Printf("%s[DEATH] %s%s was killed by a %s", cChatColor::Red.c_str(), cChatColor::White.c_str(), GetName().c_str(), KillerClass.c_str()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -101,7 +101,21 @@ static cDistortedHeightmap::sBlockInfo tbMycelium[] =
|
||||||
{E_BLOCK_DIRT, 0},
|
{E_BLOCK_DIRT, 0},
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
static cDistortedHeightmap::sBlockInfo tbGravel[] =
|
||||||
|
{
|
||||||
|
{E_BLOCK_GRAVEL, 0},
|
||||||
|
{E_BLOCK_GRAVEL, 0},
|
||||||
|
{E_BLOCK_GRAVEL, 0},
|
||||||
|
{E_BLOCK_STONE, 0},
|
||||||
|
} ;
|
||||||
|
|
||||||
|
static cDistortedHeightmap::sBlockInfo tbStone[] =
|
||||||
|
{
|
||||||
|
{E_BLOCK_STONE, 0},
|
||||||
|
{E_BLOCK_STONE, 0},
|
||||||
|
{E_BLOCK_STONE, 0},
|
||||||
|
{E_BLOCK_STONE, 0},
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -146,6 +160,8 @@ static cPattern patDirt (tbDirt, ARRAYCOUNT(tbDirt));
|
||||||
static cPattern patPodzol (tbPodzol, ARRAYCOUNT(tbPodzol));
|
static cPattern patPodzol (tbPodzol, ARRAYCOUNT(tbPodzol));
|
||||||
static cPattern patGrassLess(tbGrassLess, ARRAYCOUNT(tbGrassLess));
|
static cPattern patGrassLess(tbGrassLess, ARRAYCOUNT(tbGrassLess));
|
||||||
static cPattern patMycelium (tbMycelium, ARRAYCOUNT(tbMycelium));
|
static cPattern patMycelium (tbMycelium, ARRAYCOUNT(tbMycelium));
|
||||||
|
static cPattern patGravel (tbGravel, ARRAYCOUNT(tbGravel));
|
||||||
|
static cPattern patStone (tbStone, ARRAYCOUNT(tbStone));
|
||||||
|
|
||||||
static cPattern patOFSand (tbOFSand, ARRAYCOUNT(tbOFSand));
|
static cPattern patOFSand (tbOFSand, ARRAYCOUNT(tbOFSand));
|
||||||
static cPattern patOFClay (tbOFClay, ARRAYCOUNT(tbOFClay));
|
static cPattern patOFClay (tbOFClay, ARRAYCOUNT(tbOFClay));
|
||||||
|
@ -648,7 +664,6 @@ void cDistortedHeightmap::ComposeColumn(cChunkDesc & a_ChunkDesc, int a_RelX, in
|
||||||
{
|
{
|
||||||
case biOcean:
|
case biOcean:
|
||||||
case biPlains:
|
case biPlains:
|
||||||
case biExtremeHills:
|
|
||||||
case biForest:
|
case biForest:
|
||||||
case biTaiga:
|
case biTaiga:
|
||||||
case biSwampland:
|
case biSwampland:
|
||||||
|
@ -671,11 +686,9 @@ void cDistortedHeightmap::ComposeColumn(cChunkDesc & a_ChunkDesc, int a_RelX, in
|
||||||
case biRoofedForest:
|
case biRoofedForest:
|
||||||
case biColdTaiga:
|
case biColdTaiga:
|
||||||
case biColdTaigaHills:
|
case biColdTaigaHills:
|
||||||
case biExtremeHillsPlus:
|
|
||||||
case biSavanna:
|
case biSavanna:
|
||||||
case biSavannaPlateau:
|
case biSavannaPlateau:
|
||||||
case biSunflowerPlains:
|
case biSunflowerPlains:
|
||||||
case biExtremeHillsM:
|
|
||||||
case biFlowerForest:
|
case biFlowerForest:
|
||||||
case biTaigaM:
|
case biTaigaM:
|
||||||
case biSwamplandM:
|
case biSwamplandM:
|
||||||
|
@ -686,7 +699,6 @@ void cDistortedHeightmap::ComposeColumn(cChunkDesc & a_ChunkDesc, int a_RelX, in
|
||||||
case biBirchForestHillsM:
|
case biBirchForestHillsM:
|
||||||
case biRoofedForestM:
|
case biRoofedForestM:
|
||||||
case biColdTaigaM:
|
case biColdTaigaM:
|
||||||
case biExtremeHillsPlusM:
|
|
||||||
case biSavannaM:
|
case biSavannaM:
|
||||||
case biSavannaPlateauM:
|
case biSavannaPlateauM:
|
||||||
{
|
{
|
||||||
|
@ -737,6 +749,30 @@ void cDistortedHeightmap::ComposeColumn(cChunkDesc & a_ChunkDesc, int a_RelX, in
|
||||||
FillColumnMesa(a_ChunkDesc, a_RelX, a_RelZ);
|
FillColumnMesa(a_ChunkDesc, a_RelX, a_RelZ);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case biExtremeHillsPlus:
|
||||||
|
case biExtremeHills:
|
||||||
|
{
|
||||||
|
// Select the pattern to use - stone or grass:
|
||||||
|
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(m_CurChunkX * cChunkDef::Width + a_RelX)) / FrequencyX;
|
||||||
|
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(m_CurChunkZ * cChunkDef::Width + a_RelZ)) / FrequencyZ;
|
||||||
|
NOISE_DATATYPE Val = m_OceanFloorSelect.CubicNoise2D(NoiseX, NoiseY);
|
||||||
|
const sBlockInfo * Pattern = (Val < -0.1) ? patStone.Get() : patGrass.Get();
|
||||||
|
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, Pattern);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case biExtremeHillsPlusM:
|
||||||
|
case biExtremeHillsM:
|
||||||
|
{
|
||||||
|
// Select the pattern to use - gravel, stone or grass:
|
||||||
|
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(m_CurChunkX * cChunkDef::Width + a_RelX)) / FrequencyX;
|
||||||
|
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(m_CurChunkZ * cChunkDef::Width + a_RelZ)) / FrequencyZ;
|
||||||
|
NOISE_DATATYPE Val = m_OceanFloorSelect.CubicNoise2D(NoiseX, NoiseY);
|
||||||
|
const sBlockInfo * Pattern = (Val < -0.9) ? patStone.Get() : ((Val > 0) ? patGravel.Get() : patGrass.Get());
|
||||||
|
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, Pattern);
|
||||||
|
return;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
ASSERT(!"Unhandled biome");
|
ASSERT(!"Unhandled biome");
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Reference in New Issue