summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml2
-rw-r--r--CMakeLists.txt7
-rw-r--r--MCServer/Plugins/.gitignore2
-rw-r--r--MCServer/Plugins/APIDump/APIDesc.lua3
-rw-r--r--MCServer/Plugins/InfoDump.lua233
-rw-r--r--src/Bindings/ManualBindings.cpp17
-rw-r--r--src/BlockID.cpp3
-rw-r--r--src/BoundingBox.cpp36
-rw-r--r--src/Chunk.h2
-rw-r--r--src/Crypto.cpp8
-rw-r--r--src/Crypto.h2
-rw-r--r--src/Entities/Entity.cpp4
-rw-r--r--src/Entities/Floater.cpp4
-rw-r--r--src/Entities/Minecart.cpp10
-rw-r--r--src/Entities/Pickup.cpp4
-rw-r--r--src/Entities/Player.cpp13
-rw-r--r--src/Entities/Player.h1
-rw-r--r--src/Group.cpp40
-rw-r--r--src/Group.h26
-rw-r--r--src/GroupManager.cpp19
-rw-r--r--src/GroupManager.h1
-rw-r--r--src/Item.h8
-rw-r--r--src/Mobs/Monster.cpp8
-rw-r--r--src/Mobs/Villager.cpp4
-rw-r--r--src/Protocol/Protocol17x.cpp4
-rw-r--r--src/Root.cpp17
-rw-r--r--src/Root.h3
-rw-r--r--src/Scoreboard.cpp2
-rw-r--r--src/Server.cpp11
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator.cpp1534
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator.h263
-rw-r--r--src/Simulator/NoopRedstoneSimulator.h40
-rw-r--r--src/Simulator/RedstoneSimulator.cpp1523
-rw-r--r--src/Simulator/RedstoneSimulator.h250
-rw-r--r--src/WebAdmin.cpp38
-rw-r--r--src/WebAdmin.h46
-rw-r--r--src/World.cpp40
-rw-r--r--src/World.h3
38 files changed, 2327 insertions, 1904 deletions
diff --git a/.travis.yml b/.travis.yml
index a41c10b84..38dd2f280 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,7 +3,7 @@ compiler:
- gcc
- clang
# Build MCServer
-script: cmake . -DCMAKE_BUILD_TYPE=RELEASE && make -j 2
+script: cmake . -DCMAKE_BUILD_TYPE=RELEASE -DSELF_TEST=1 && make -j 2 && cd MCServer/ && (echo stop | ./MCServer)
# Notification Settings
notifications:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c40767d20..57b200a2a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -60,6 +60,9 @@ else()
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++11")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++11")
endif()
+
+ # We use a signed char (fixes #640 on RasPi)
+ add_flags_cxx("-fsigned-char")
endif()
@@ -121,6 +124,10 @@ endif()
# The Expat library is linked in statically, make the source files aware of that:
add_definitions(-DXML_STATIC)
+# Self Test Mode enables extra checks at startup
+if(${SELF_TEST})
+ add_definitions(-DSELF_TEST)
+endif()
# Declare the flags used for profiling builds:
if (MSVC)
diff --git a/MCServer/Plugins/.gitignore b/MCServer/Plugins/.gitignore
new file mode 100644
index 000000000..89eab800a
--- /dev/null
+++ b/MCServer/Plugins/.gitignore
@@ -0,0 +1,2 @@
+*.txt
+*.md
diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua
index 61de0c1a6..c0056ac4a 100644
--- a/MCServer/Plugins/APIDump/APIDesc.lua
+++ b/MCServer/Plugins/APIDump/APIDesc.lua
@@ -1748,10 +1748,11 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage);
GetCommandPermission = { Params = "Command", Return = "Permission", Notes = "Returns the permission needed for executing the specified command" },
GetCurrentPlugin = { Params = "", Return = "{{cPlugin}}", Notes = "Returns the {{cPlugin}} object for the calling plugin. This is the same object that the Initialize function receives as the argument." },
GetNumPlugins = { Params = "", Return = "number", Notes = "Returns the number of plugins, including the disabled ones" },
- GetPlugin = { Params = "PluginName", Return = "{{cPlugin}}", Notes = "Returns a plugin handle of the specified plugin" },
+ GetPlugin = { Params = "PluginName", Return = "{{cPlugin}}", Notes = "(<b>DEPRECATED, UNSAFE</b>) Returns a plugin handle of the specified plugin, or nil if such plugin is not loaded. Note thatdue to multithreading the handle is not guaranteed to be safe for use when stored - a single-plugin reload may have been triggered in the mean time for the requested plugin." },
IsCommandBound = { Params = "Command", Return = "bool", Notes = "Returns true if in-game Command is already bound (by any plugin)" },
IsConsoleCommandBound = { Params = "Command", Return = "bool", Notes = "Returns true if console Command is already bound (by any plugin)" },
LoadPlugin = { Params = "PluginFolder", Return = "", Notes = "(<b>DEPRECATED</b>) Loads a plugin from the specified folder. NOTE: Loading plugins may be an unsafe operation and may result in a deadlock or a crash. This API is deprecated and might be removed." },
+ LogStackTrace = { Params = "", Return = "", Notes = "(STATIC) Logs a current stack trace of the Lua engine to the server console log. Same format as is used when the plugin fails." },
ReloadPlugins = { Params = "", Return = "", Notes = "Reloads all active plugins" },
},
Constants =
diff --git a/MCServer/Plugins/InfoDump.lua b/MCServer/Plugins/InfoDump.lua
index 28a17c214..8fac09d60 100644
--- a/MCServer/Plugins/InfoDump.lua
+++ b/MCServer/Plugins/InfoDump.lua
@@ -69,6 +69,47 @@ end
+--- Replaces generic formatting with forum-specific formatting
+-- Also removes the single line-ends
+local function GithubizeString(a_Str)
+ assert(type(a_Str) == "string");
+
+ -- Remove the indentation, unless in the code tag:
+ -- Only one code or /code tag per line is supported!
+ local IsInCode = false;
+ local function RemoveIndentIfNotInCode(s)
+ if (IsInCode) then
+ -- we're in code section, check if this line terminates it
+ IsInCode = (s:find("{%%/code}") ~= nil);
+ return s .. "\n";
+ else
+ -- we're not in code section, check if this line starts it
+ IsInCode = (s:find("{%%code}") ~= nil);
+ return s:gsub("^%s*", "") .. "\n";
+ end
+ end
+ a_Str = a_Str:gsub("(.-)\n", RemoveIndentIfNotInCode);
+
+ -- Replace multiple line ends with {%p} and single line ends with a space,
+ -- so that manual word-wrap in the Info.lua file doesn't wrap in the forum.
+ a_Str = a_Str:gsub("\n\n", "{%%p}");
+ a_Str = a_Str:gsub("\n", " ");
+
+ -- Replace the generic formatting:
+ a_Str = a_Str:gsub("{%%p}", "\n\n");
+ a_Str = a_Str:gsub("{%%b}", "**"):gsub("{%%/b}", "**");
+ a_Str = a_Str:gsub("{%%i}", "*"):gsub("{%%/i}", "*");
+ a_Str = a_Str:gsub("{%%list}", ""):gsub("{%%/list}", "");
+ a_Str = a_Str:gsub("{%%li}", " - "):gsub("{%%/li}", "");
+ -- TODO: Other formatting
+
+ return a_Str;
+end
+
+
+
+
+
--- Builds an array of categories, each containing all the commands belonging to the category,
-- and the category description, if available.
-- Returns the array table, each item has the following format:
@@ -156,6 +197,28 @@ end
+--- Returns a string specifying the command.
+-- If a_CommandParams is nil, returns a_CommandName apostrophed
+-- If a_CommandParams is a string, apostrophes a_CommandName with a_CommandParams
+local function GetCommandRefGithub(a_CommandName, a_CommandParams)
+ assert(type(a_CommandName) == "string");
+ if (a_CommandParams == nil) then
+ return "`" .. a_CommandName .. "`";
+ end
+
+ assert(type(a_CommandParams) == "table");
+ if ((a_CommandParams.Params == nil) or (a_CommandParams.Params == "")) then
+ return "`" .. a_CommandName .. "`";
+ end
+
+ assert(type(a_CommandParams.Params) == "string");
+ return "`" .. a_CommandName .. " " .. a_CommandParams.Params .. "`";
+end
+
+
+
+
+
--- Writes the specified command detailed help array to the output file, in the forum dump format
local function WriteCommandParameterCombinationsForum(a_CmdString, a_ParameterCombinations, f)
assert(type(a_CmdString) == "string");
@@ -184,6 +247,34 @@ end
+--- Writes the specified command detailed help array to the output file, in the forum dump format
+local function WriteCommandParameterCombinationsGithub(a_CmdString, a_ParameterCombinations, f)
+ assert(type(a_CmdString) == "string");
+ assert(type(a_ParameterCombinations) == "table");
+ assert(f ~= nil);
+
+ if (#a_ParameterCombinations == 0) then
+ -- No explicit parameter combinations to write
+ return;
+ end
+
+ f:write("The following parameter combinations are recognized:\n\n");
+ for idx, combination in ipairs(a_ParameterCombinations) do
+ f:write(GetCommandRefGithub(a_CmdString, combination));
+ if (combination.Help ~= nil) then
+ f:write(" - ", GithubizeString(combination.Help));
+ end
+ if (combination.Permission ~= nil) then
+ f:write(" (Requires permission '**", combination.Permission, "**')");
+ end
+ f:write("\n");
+ end
+end
+
+
+
+
+
--- Writes all commands in the specified category to the output file, in the forum dump format
local function WriteCommandsCategoryForum(a_Category, f)
-- Write category name:
@@ -206,7 +297,7 @@ local function WriteCommandsCategoryForum(a_Category, f)
f:write("Permission required: [color=red]", cmd.Info.Permission, "[/color]\n");
end
if (cmd.Info.DetailedDescription ~= nil) then
- f:write(cmd.Info.DetailedDescription);
+ f:write(ForumizeString(cmd.Info.DetailedDescription));
end
if (cmd.Info.ParameterCombinations ~= nil) then
WriteCommandParameterCombinationsForum(cmd.CommandString, cmd.Info.ParameterCombinations, f);
@@ -219,6 +310,41 @@ end
+--- Writes all commands in the specified category to the output file, in the Github dump format
+local function WriteCommandsCategoryGithub(a_Category, f)
+ -- Write category name:
+ local CategoryName = a_Category.Name;
+ if (CategoryName == "") then
+ CategoryName = "General";
+ end
+ f:write("\n## ", GithubizeString(a_Category.DisplayName or CategoryName), "\n");
+
+ -- Write description:
+ if (a_Category.Description ~= "") then
+ f:write(GithubizeString(a_Category.Description), "\n");
+ end
+
+ -- Write commands:
+ f:write("\n");
+ for idx2, cmd in ipairs(a_Category.Commands) do
+ f:write("\n### ", cmd.CommandString, "\n", GithubizeString(cmd.Info.HelpString or "UNDOCUMENTED"), "\n\n");
+ if (cmd.Info.Permission ~= nil) then
+ f:write("Permission required: **", cmd.Info.Permission, "**\n\n");
+ end
+ if (cmd.Info.DetailedDescription ~= nil) then
+ f:write(GithubizeString(cmd.Info.DetailedDescription));
+ end
+ if (cmd.Info.ParameterCombinations ~= nil) then
+ WriteCommandParameterCombinationsGithub(cmd.CommandString, cmd.Info.ParameterCombinations, f);
+ end
+ end
+ f:write("\n\n")
+end
+
+
+
+
+
local function DumpCommandsForum(a_PluginInfo, f)
-- Copy all Categories from a dictionary into an array:
local Categories = BuildCategories(a_PluginInfo);
@@ -246,9 +372,36 @@ end
+local function DumpCommandsGithub(a_PluginInfo, f)
+ -- Copy all Categories from a dictionary into an array:
+ local Categories = BuildCategories(a_PluginInfo);
+
+ -- Sort the categories by name:
+ table.sort(Categories,
+ function(cat1, cat2)
+ return (string.lower(cat1.Name) < string.lower(cat2.Name));
+ end
+ );
+
+ if (#Categories == 0) then
+ return;
+ end
+
+ f:write("\n# Commands\n");
+
+ -- Dump per-category commands:
+ for idx, cat in ipairs(Categories) do
+ WriteCommandsCategoryGithub(cat, f);
+ end
+end
+
+
+
+
+
local function DumpAdditionalInfoForum(a_PluginInfo, f)
local AInfo = a_PluginInfo.AdditionalInfo;
- if ((AInfo == nil) or (type(AInfo) ~= "table")) then
+ if (type(AInfo) ~= "table") then
-- There is no AdditionalInfo in a_PluginInfo
return;
end
@@ -265,6 +418,25 @@ end
+local function DumpAdditionalInfoGithub(a_PluginInfo, f)
+ local AInfo = a_PluginInfo.AdditionalInfo;
+ if (type(AInfo) ~= "table") then
+ -- There is no AdditionalInfo in a_PluginInfo
+ return;
+ end
+
+ for idx, info in ipairs(a_PluginInfo.AdditionalInfo) do
+ if ((info.Title ~= nil) and (info.Contents ~= nil)) then
+ f:write("\n# ", GithubizeString(info.Title), "\n");
+ f:write(GithubizeString(info.Contents), "\n");
+ end
+ end
+end
+
+
+
+
+
--- Collects all permissions mentioned in the info, returns them as a sorted array
-- Each array item is {Name = "PermissionName", Info = { PermissionInfo }}
local function BuildPermissions(a_PluginInfo)
@@ -333,7 +505,7 @@ local function DumpPermissionsForum(a_PluginInfo, f)
f:write("\n[size=X-Large]Permissions[/size]\n[list]\n");
for idx, perm in ipairs(Permissions) do
f:write(" - [color=red]", perm.Name, "[/color] - ");
- f:write(perm.Info.Description or "");
+ f:write(ForumizeString(perm.Info.Description or ""));
local CommandsAffected = perm.Info.CommandsAffected or {};
if (#CommandsAffected > 0) then
f:write("\n[list] Commands affected:\n- ");
@@ -356,6 +528,43 @@ end
+local function DumpPermissionsGithub(a_PluginInfo, f)
+ -- Get the processed sorted array of permissions:
+ local Permissions = BuildPermissions(a_PluginInfo);
+ if ((Permissions == nil) or (#Permissions <= 0)) then
+ return;
+ end
+
+ -- Dump the permissions:
+ f:write("\n# Permissions\n");
+ for idx, perm in ipairs(Permissions) do
+ f:write("### ", perm.Name, "\n");
+ f:write(GithubizeString(perm.Info.Description or ""));
+ local CommandsAffected = perm.Info.CommandsAffected or {};
+ if (#CommandsAffected > 0) then
+ f:write("\n\nCommands affected:\n - ");
+ local Affects = {};
+ for idx2, cmd in ipairs(CommandsAffected) do
+ if (type(cmd) == "string") then
+ table.insert(Affects, GetCommandRefGithub(cmd));
+ else
+ table.insert(Affects, GetCommandRefGithub(cmd.Name, cmd));
+ end
+ end
+ f:write(table.concat(Affects, "\n - "));
+ f:write("\n");
+ end
+ if (perm.Info.RecommendedGroups ~= nil) then
+ f:write("\n\nRecommended groups: ", perm.Info.RecommendedGroups, "\n");
+ end
+ f:write("\n");
+ end
+end
+
+
+
+
+
local function DumpPluginInfoForum(a_PluginFolder, a_PluginInfo)
-- Open the output file:
local f, msg = io.open(a_PluginInfo.Name .. "_forum.txt", "w");
@@ -377,8 +586,21 @@ end
-local function DumpPluginInfoGitHub()
- -- TODO
+local function DumpPluginInfoGithub(a_PluginFolder, a_PluginInfo)
+ -- Open the output file:
+ local f, msg = io.open(a_PluginInfo.Name .. ".md", "w"); -- TODO: Save to a_PluginFolder .. "/Readme.md" instead
+ if (f == nil) then
+ print("\tCannot dump github info for plugin " .. a_PluginFolder .. ": " .. msg);
+ return;
+ end
+
+ -- Write the description:
+ f:write(GithubizeString(a_PluginInfo.Description), "\n");
+ DumpAdditionalInfoGithub(a_PluginInfo, f);
+ DumpCommandsGithub(a_PluginInfo, f);
+ DumpPermissionsGithub(a_PluginInfo, f);
+
+ f:close();
end
@@ -418,6 +640,7 @@ local function ProcessPluginFolder(a_FolderName)
return;
end
DumpPluginInfoForum(a_FolderName, PluginInfo);
+ DumpPluginInfoGithub(a_FolderName, PluginInfo);
end
diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp
index 9ebdc4b22..841ec5cf2 100644
--- a/src/Bindings/ManualBindings.cpp
+++ b/src/Bindings/ManualBindings.cpp
@@ -906,8 +906,12 @@ static int tolua_cWorld_TryGetHeight(lua_State * tolua_S)
{
int Height = 0;
bool res = self->TryGetHeight(BlockX, BlockZ, Height);
- tolua_pushnumber(tolua_S, Height);
tolua_pushboolean(tolua_S, res ? 1 : 0);
+ if (res)
+ {
+ tolua_pushnumber(tolua_S, Height);
+ return 2;
+ }
}
}
return 1;
@@ -1106,6 +1110,16 @@ static int tolua_cPluginManager_GetCurrentPlugin(lua_State * S)
+static int tolua_cPluginManager_LogStackTrace(lua_State * S)
+{
+ cLuaState::LogStackTrace(S);
+ return 0;
+}
+
+
+
+
+
static int tolua_cPluginManager_AddHook_FnRef(cPluginManager * a_PluginManager, cLuaState & S, int a_ParamIdx)
{
// Helper function for cPluginmanager:AddHook() binding
@@ -2386,6 +2400,7 @@ void ManualBindings::Bind(lua_State * tolua_S)
tolua_function(tolua_S, "ForEachConsoleCommand", tolua_cPluginManager_ForEachConsoleCommand);
tolua_function(tolua_S, "GetAllPlugins", tolua_cPluginManager_GetAllPlugins);
tolua_function(tolua_S, "GetCurrentPlugin", tolua_cPluginManager_GetCurrentPlugin);
+ tolua_function(tolua_S, "LogStackTrace", tolua_cPluginManager_LogStackTrace);
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cPlayer");
diff --git a/src/BlockID.cpp b/src/BlockID.cpp
index de56d4625..c38db0bfe 100644
--- a/src/BlockID.cpp
+++ b/src/BlockID.cpp
@@ -380,7 +380,7 @@ AString DamageTypeToString(eDamageType a_DamageType)
case dtRangedAttack: return "dtRangedAttack";
case dtStarving: return "dtStarving";
case dtSuffocating: return "dtSuffocation";
-
+ case dtExplosion: return "dtExplosion";
}
// Unknown damage type:
@@ -426,6 +426,7 @@ eDamageType StringToDamageType(const AString & a_DamageTypeString)
{ dtInVoid, "dtInVoid"},
{ dtPotionOfHarming, "dtPotionOfHarming"},
{ dtAdmin, "dtAdmin"},
+ { dtExplosion, "dtExplosion"},
// Common synonyms:
{ dtAttack, "dtPawnAttack"},
diff --git a/src/BoundingBox.cpp b/src/BoundingBox.cpp
index 86d4546c7..47b135688 100644
--- a/src/BoundingBox.cpp
+++ b/src/BoundingBox.cpp
@@ -1,4 +1,3 @@
-
// BoundingBox.cpp
// Implements the cBoundingBox class representing an axis-aligned bounding box with floatingpoint coords
@@ -11,7 +10,7 @@
-#if 0
+#if SELF_TEST
/// A simple self-test that is executed on program start, used to verify bbox functionality
class SelfTest
@@ -30,20 +29,39 @@ public:
Vector3d(1.999, 0, 1.5), Vector3d(1.999, 4, 1.5), // Should intersect at 0.25, face 0 (YM)
Vector3d(2.001, 0, 1.5), Vector3d(2.001, 4, 1.5), // Should not intersect
} ;
+ bool Results[] = {true,true,true,false,true,false};
+ double LineCoeffs[] = {2,0.25,0.5,0,0.25,0};
+
for (size_t i = 0; i < ARRAYCOUNT(LineDefs) / 2; i++)
{
double LineCoeff;
- char Face;
+ eBlockFace Face;
Vector3d Line1 = LineDefs[2 * i];
Vector3d Line2 = LineDefs[2 * i + 1];
bool res = cBoundingBox::CalcLineIntersection(Min, Max, Line1, Line2, LineCoeff, Face);
- printf("LineIntersection({%.02f, %.02f, %.02f}, {%.02f, %.02f, %.02f}) -> %d, %.05f, %d\n",
- Line1.x, Line1.y, Line1.z,
- Line2.x, Line2.y, Line2.z,
- res ? 1 : 0, LineCoeff, Face
- );
+ if (res != Results[i])
+ {
+ fprintf(stderr,"LineIntersection({%.02f, %.02f, %.02f}, {%.02f, %.02f, %.02f}) -> %d, %.05f, %d\n",
+ Line1.x, Line1.y, Line1.z,
+ Line2.x, Line2.y, Line2.z,
+ res ? 1 : 0, LineCoeff, Face
+ );
+ abort();
+ }
+ if (res)
+ {
+ if (LineCoeff != LineCoeffs[i])
+ {
+ fprintf(stderr,"LineIntersection({%.02f, %.02f, %.02f}, {%.02f, %.02f, %.02f}) -> %d, %.05f, %d\n",
+ Line1.x, Line1.y, Line1.z,
+ Line2.x, Line2.y, Line2.z,
+ res ? 1 : 0, LineCoeff, Face
+ );
+ abort();
+ }
+ }
} // for i - LineDefs[]
- printf("BoundingBox selftest complete.");
+ fprintf(stderr,"BoundingBox selftest complete.");
}
} Test;
diff --git a/src/Chunk.h b/src/Chunk.h
index 83d69d12c..3dc83b157 100644
--- a/src/Chunk.h
+++ b/src/Chunk.h
@@ -6,7 +6,7 @@
#include "Simulator/FireSimulator.h"
#include "Simulator/SandSimulator.h"
-#include "Simulator/RedstoneSimulator.h"
+#include "Simulator/IncrementalRedstoneSimulator.h"
diff --git a/src/Crypto.cpp b/src/Crypto.cpp
index 7a06d7fa3..26500f263 100644
--- a/src/Crypto.cpp
+++ b/src/Crypto.cpp
@@ -308,8 +308,8 @@ void cPublicKey::InitRnd(void)
// cAESCFBDecryptor:
cAESCFBDecryptor::cAESCFBDecryptor(void) :
- m_IsValid(false),
- m_IVOffset(0)
+ m_IVOffset(0),
+ m_IsValid(false)
{
}
@@ -366,8 +366,8 @@ void cAESCFBDecryptor::ProcessData(Byte * a_DecryptedOut, const Byte * a_Encrypt
// cAESCFBEncryptor:
cAESCFBEncryptor::cAESCFBEncryptor(void) :
- m_IsValid(false),
- m_IVOffset(0)
+ m_IVOffset(0),
+ m_IsValid(false)
{
}
diff --git a/src/Crypto.h b/src/Crypto.h
index d68f7ec24..a9ec2c6d4 100644
--- a/src/Crypto.h
+++ b/src/Crypto.h
@@ -132,8 +132,6 @@ protected:
class cAESCFBEncryptor
{
public:
- Byte test;
-
cAESCFBEncryptor(void);
~cAESCFBEncryptor();
diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp
index 08780ca8b..8554ab2a5 100644
--- a/src/Entities/Entity.cpp
+++ b/src/Entities/Entity.cpp
@@ -50,6 +50,8 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d
, m_TicksSinceLastFireDamage(0)
, m_TicksLeftBurning(0)
, m_TicksSinceLastVoidDamage(0)
+ , m_IsSwimming(false)
+ , m_IsSubmerged(false)
, m_HeadYaw( 0.0 )
, m_Rot(0.0, 0.0, 0.0)
, m_Pos(a_X, a_Y, a_Z)
@@ -57,8 +59,6 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d
, m_Mass (0.001) // Default 1g
, m_Width(a_Width)
, m_Height(a_Height)
- , m_IsSubmerged(false)
- , m_IsSwimming(false)
{
cCSLock Lock(m_CSCount);
m_EntityCount++;
diff --git a/src/Entities/Floater.cpp b/src/Entities/Floater.cpp
index 38160a30e..b910c3769 100644
--- a/src/Entities/Floater.cpp
+++ b/src/Entities/Floater.cpp
@@ -103,10 +103,10 @@ protected:
cFloater::cFloater(double a_X, double a_Y, double a_Z, Vector3d a_Speed, int a_PlayerID, int a_CountDownTime) :
cEntity(etFloater, a_X, a_Y, a_Z, 0.2, 0.2),
- m_PickupCountDown(0),
- m_PlayerID(a_PlayerID),
m_CanPickupItem(false),
+ m_PickupCountDown(0),
m_CountDownTime(a_CountDownTime),
+ m_PlayerID(a_PlayerID),
m_AttachedMobID(-1)
{
SetSpeed(a_Speed);
diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp
index a650927b1..d854906b7 100644
--- a/src/Entities/Minecart.cpp
+++ b/src/Entities/Minecart.cpp
@@ -24,11 +24,11 @@ class cMinecartCollisionCallback :
{
public:
cMinecartCollisionCallback(Vector3d a_Pos, double a_Height, double a_Width, int a_UniqueID, int a_AttacheeUniqueID) :
+ m_DoesInteserct(false),
+ m_CollidedEntityPos(0, 0, 0),
m_Pos(a_Pos),
m_Height(a_Height),
m_Width(a_Width),
- m_DoesInteserct(false),
- m_CollidedEntityPos(0, 0, 0),
m_UniqueID(a_UniqueID),
m_AttacheeUniqueID(a_AttacheeUniqueID)
{
@@ -1057,8 +1057,8 @@ void cMinecartWithChest::OnRightClicked(cPlayer & a_Player)
cMinecartWithFurnace::cMinecartWithFurnace(double a_X, double a_Y, double a_Z) :
super(mpFurnace, a_X, a_Y, a_Z),
- m_IsFueled(false),
- m_FueledTimeLeft(-1)
+ m_FueledTimeLeft(-1),
+ m_IsFueled(false)
{
}
@@ -1137,4 +1137,4 @@ cMinecartWithHopper::cMinecartWithHopper(double a_X, double a_Y, double a_Z) :
}
// TODO: Make it suck up blocks and travel further than any other cart and physics and put and take blocks
-// AND AVARYTHING!! \ No newline at end of file
+// AND AVARYTHING!!
diff --git a/src/Entities/Pickup.cpp b/src/Entities/Pickup.cpp
index bfe162b69..c5503c16a 100644
--- a/src/Entities/Pickup.cpp
+++ b/src/Entities/Pickup.cpp
@@ -22,9 +22,9 @@ class cPickupCombiningCallback :
{
public:
cPickupCombiningCallback(Vector3d a_Position, cPickup * a_Pickup) :
+ m_FoundMatchingPickup(false),
m_Position(a_Position),
- m_Pickup(a_Pickup),
- m_FoundMatchingPickup(false)
+ m_Pickup(a_Pickup)
{
}
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index eef6b8e69..286d43cf6 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -1261,19 +1261,6 @@ void cPlayer::RemoveFromGroup( const AString & a_GroupName )
-bool cPlayer::CanUseCommand( const AString & a_Command )
-{
- for( GroupList::iterator itr = m_Groups.begin(); itr != m_Groups.end(); ++itr )
- {
- if( (*itr)->HasCommand( a_Command ) ) return true;
- }
- return false;
-}
-
-
-
-
-
bool cPlayer::HasPermission(const AString & a_Permission)
{
if (a_Permission.empty())
diff --git a/src/Entities/Player.h b/src/Entities/Player.h
index 869e67775..7db9544cb 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -218,7 +218,6 @@ public:
/// Removes a player from the group, resolves permissions and group inheritance (case sensitive)
void RemoveFromGroup( const AString & a_GroupName ); // tolua_export
- bool CanUseCommand( const AString & a_Command ); // tolua_export
bool HasPermission( const AString & a_Permission ); // tolua_export
const GroupList & GetGroups() { return m_Groups; } // >> EXPORTED IN MANUALBINDINGS <<
StringList GetResolvedPermissions(); // >> EXPORTED IN MANUALBINDINGS <<
diff --git a/src/Group.cpp b/src/Group.cpp
index 448d29d87..5f1f25782 100644
--- a/src/Group.cpp
+++ b/src/Group.cpp
@@ -3,35 +3,39 @@
#include "Group.h"
-void cGroup::AddCommand( std::string a_Command )
+
+
+
+
+void cGroup::AddCommand( AString a_Command )
{
m_Commands[ a_Command ] = true;
}
-void cGroup::AddPermission( std::string a_Permission )
+
+
+
+
+void cGroup::AddPermission( AString a_Permission )
{
m_Permissions[ a_Permission ] = true;
}
-bool cGroup::HasCommand( std::string a_Command )
-{
- if( m_Commands.find("*") != m_Commands.end() ) return true;
-
- CommandMap::iterator itr = m_Commands.find( a_Command );
- if( itr != m_Commands.end() )
- {
- if( itr->second ) return true;
- }
-
- for( GroupList::iterator itr = m_Inherits.begin(); itr != m_Inherits.end(); ++itr )
- {
- if( (*itr)->HasCommand( a_Command ) ) return true;
- }
- return false;
-}
+
+
+
void cGroup::InheritFrom( cGroup* a_Group )
{
m_Inherits.remove( a_Group );
m_Inherits.push_back( a_Group );
+}
+
+
+
+
+
+void cGroup::ClearPermission()
+{
+ m_Permissions.clear();
} \ No newline at end of file
diff --git a/src/Group.h b/src/Group.h
index 65ee1a60a..8bee6f7ed 100644
--- a/src/Group.h
+++ b/src/Group.h
@@ -11,19 +11,19 @@ public: // tolua_export
cGroup() {}
~cGroup() {}
- void SetName( std::string a_Name ) { m_Name = a_Name; } // tolua_export
- const std::string & GetName() const { return m_Name; } // tolua_export
- void SetColor( std::string a_Color ) { m_Color = a_Color; } // tolua_export
- void AddCommand( std::string a_Command ); // tolua_export
- void AddPermission( std::string a_Permission ); // tolua_export
- void InheritFrom( cGroup* a_Group ); // tolua_export
-
- bool HasCommand( std::string a_Command ); // tolua_export
-
- typedef std::map< std::string, bool > PermissionMap;
+ void SetName( AString a_Name ) { m_Name = a_Name; } // tolua_export
+ const AString & GetName() const { return m_Name; } // tolua_export
+ void SetColor( AString a_Color ) { m_Color = a_Color; } // tolua_export
+ void AddCommand( AString a_Command ); // tolua_export
+ void AddPermission( AString a_Permission ); // tolua_export
+ void InheritFrom( cGroup* a_Group ); // tolua_export
+
+ typedef std::map< AString, bool > PermissionMap;
const PermissionMap & GetPermissions() const { return m_Permissions; }
- typedef std::map< std::string, bool > CommandMap;
+ void ClearPermission(void);
+
+ typedef std::map< AString, bool > CommandMap;
const CommandMap & GetCommands() const { return m_Commands; }
const AString & GetColor() const { return m_Color; } // tolua_export
@@ -31,8 +31,8 @@ public: // tolua_export
typedef std::list< cGroup* > GroupList;
const GroupList & GetInherits() const { return m_Inherits; }
private:
- std::string m_Name;
- std::string m_Color;
+ AString m_Name;
+ AString m_Color;
PermissionMap m_Permissions;
CommandMap m_Commands;
diff --git a/src/GroupManager.cpp b/src/GroupManager.cpp
index d5567d91e..723b86f94 100644
--- a/src/GroupManager.cpp
+++ b/src/GroupManager.cpp
@@ -44,6 +44,18 @@ cGroupManager::cGroupManager()
: m_pState( new sGroupManagerState )
{
LOGD("-- Loading Groups --");
+
+ LoadGroups();
+
+ LOGD("-- Groups Successfully Loaded --");
+}
+
+
+
+
+
+void cGroupManager::LoadGroups()
+{
cIniFile IniFile;
if (!IniFile.ReadFile("groups.ini"))
{
@@ -71,8 +83,10 @@ cGroupManager::cGroupManager()
unsigned int NumKeys = IniFile.GetNumKeys();
for (size_t i = 0; i < NumKeys; i++)
{
- std::string KeyName = IniFile.GetKeyName( i );
+ AString KeyName = IniFile.GetKeyName( i );
cGroup* Group = GetGroup( KeyName.c_str() );
+
+ Group->ClearPermission(); // Needed in case the groups are reloaded.
LOGD("Loading group: %s", KeyName.c_str() );
@@ -107,7 +121,7 @@ cGroupManager::cGroupManager()
}
}
- std::string Groups = IniFile.GetValue(KeyName, "Inherits", "");
+ AString Groups = IniFile.GetValue(KeyName, "Inherits", "");
if (!Groups.empty())
{
AStringVector Split = StringSplitAndTrim(Groups, ",");
@@ -117,7 +131,6 @@ cGroupManager::cGroupManager()
}
}
}
- LOGD("-- Groups Successfully Loaded --");
}
diff --git a/src/GroupManager.h b/src/GroupManager.h
index d911f976c..02a58fe4e 100644
--- a/src/GroupManager.h
+++ b/src/GroupManager.h
@@ -15,6 +15,7 @@ class cGroupManager
{
public:
cGroup * GetGroup(const AString & a_Name);
+ void LoadGroups(void);
private:
friend class cRoot;
diff --git a/src/Item.h b/src/Item.h
index ca9ec5a2b..4782f31c1 100644
--- a/src/Item.h
+++ b/src/Item.h
@@ -55,9 +55,9 @@ public:
m_ItemType (a_ItemType),
m_ItemCount (a_ItemCount),
m_ItemDamage (a_ItemDamage),
- m_Enchantments(a_Enchantments),
m_CustomName (a_CustomName),
- m_Lore (a_Lore)
+ m_Lore (a_Lore),
+ m_Enchantments(a_Enchantments)
{
if (!IsValidItem(m_ItemType))
{
@@ -75,9 +75,9 @@ public:
m_ItemType (a_CopyFrom.m_ItemType),
m_ItemCount (a_CopyFrom.m_ItemCount),
m_ItemDamage (a_CopyFrom.m_ItemDamage),
- m_Enchantments(a_CopyFrom.m_Enchantments),
m_CustomName (a_CopyFrom.m_CustomName),
- m_Lore (a_CopyFrom.m_Lore)
+ m_Lore (a_CopyFrom.m_Lore),
+ m_Enchantments(a_CopyFrom.m_Enchantments)
{
}
diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp
index 86ff522d8..ad3a87725 100644
--- a/src/Mobs/Monster.cpp
+++ b/src/Mobs/Monster.cpp
@@ -69,20 +69,20 @@ cMonster::cMonster(const AString & a_ConfigName, eType a_MobType, const AString
: super(etMonster, a_Width, a_Height)
, m_EMState(IDLE)
, m_EMPersonality(AGGRESSIVE)
- , m_SightDistance(25)
, m_Target(NULL)
- , m_AttackRate(3)
- , m_IdleInterval(0)
, m_bMovingToDestination(false)
+ , m_LastGroundHeight(POSY_TOINT)
+ , m_IdleInterval(0)
, m_DestroyTimer(0)
, m_MobType(a_MobType)
, m_SoundHurt(a_SoundHurt)
, m_SoundDeath(a_SoundDeath)
+ , m_AttackRate(3)
, m_AttackDamage(1)
, m_AttackRange(2)
, m_AttackInterval(0)
+ , m_SightDistance(25)
, m_BurnsInDaylight(false)
- , m_LastGroundHeight(POSY_TOINT)
{
if (!a_ConfigName.empty())
{
diff --git a/src/Mobs/Villager.cpp b/src/Mobs/Villager.cpp
index 08e5e4315..09a6e2d09 100644
--- a/src/Mobs/Villager.cpp
+++ b/src/Mobs/Villager.cpp
@@ -13,9 +13,9 @@
cVillager::cVillager(eVillagerType VillagerType) :
super("Villager", mtVillager, "", "", 0.6, 1.8),
+ m_ActionCountDown(-1),
m_Type(VillagerType),
- m_VillagerAction(false),
- m_ActionCountDown(-1)
+ m_VillagerAction(false)
{
}
diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp
index 262ee4c0e..7eaf106cf 100644
--- a/src/Protocol/Protocol17x.cpp
+++ b/src/Protocol/Protocol17x.cpp
@@ -99,7 +99,7 @@ void cProtocol172::DataReceived(const char * a_Data, int a_Size)
Byte Decrypted[512];
while (a_Size > 0)
{
- int NumBytes = (a_Size > sizeof(Decrypted)) ? sizeof(Decrypted) : a_Size;
+ size_t NumBytes = (a_Size > sizeof(Decrypted)) ? sizeof(Decrypted) : a_Size;
m_Decryptor.ProcessData(Decrypted, (Byte *)a_Data, NumBytes);
AddReceivedData((const char *)Decrypted, NumBytes);
a_Size -= NumBytes;
@@ -1836,7 +1836,7 @@ void cProtocol172::SendData(const char * a_Data, int a_Size)
Byte Encrypted[8192]; // Larger buffer, we may be sending lots of data (chunks)
while (a_Size > 0)
{
- int NumBytes = (a_Size > sizeof(Encrypted)) ? sizeof(Encrypted) : a_Size;
+ size_t NumBytes = ((size_t)a_Size > sizeof(Encrypted)) ? sizeof(Encrypted) : (size_t)a_Size;
m_Encryptor.ProcessData(Encrypted, (Byte *)a_Data, NumBytes);
m_Client->SendData((const char *)Encrypted, NumBytes);
a_Size -= NumBytes;
diff --git a/src/Root.cpp b/src/Root.cpp
index 3e1898c42..749fbd288 100644
--- a/src/Root.cpp
+++ b/src/Root.cpp
@@ -132,7 +132,7 @@ void cRoot::Start(void)
LOGWARN("Regenerating settings.ini, all settings will be reset");
IniFile.AddHeaderComment(" This is the main server configuration");
IniFile.AddHeaderComment(" Most of the settings here can be configured using the webadmin interface, if enabled in webadmin.ini");
- IniFile.AddHeaderComment(" See: http://www.mc-server.org/wiki/doku.php?id=configure:settings.ini for further configuration help");
+ IniFile.AddHeaderComment(" See: http://wiki.mc-server.org/doku.php?id=configure:settings.ini for further configuration help");
}
m_PrimaryServerVersion = IniFile.GetValueI("Server", "PrimaryServerVersion", 0);
@@ -219,16 +219,14 @@ void cRoot::Start(void)
delete m_InputThread; m_InputThread = NULL;
#endif
- // Deallocate stuffs
+ // Stop the server:
+ m_WebAdmin->Stop();
LOG("Shutting down server...");
m_Server->Shutdown();
-
LOGD("Shutting down deadlock detector...");
dd.Stop();
-
LOGD("Stopping world threads...");
StopWorlds();
-
LOGD("Stopping authenticator...");
m_Authenticator.Stop();
@@ -536,6 +534,15 @@ void cRoot::SaveAllChunks(void)
+void cRoot::ReloadGroups(void)
+{
+ m_GroupManager->LoadGroups();
+}
+
+
+
+
+
void cRoot::LoopWorldsAndBroadcastChat(const AString & a_Message, ChatPrefixCodes a_ChatPrefix)
{
for (WorldMap::iterator itr = m_WorldsByName.begin(), end = m_WorldsByName.end(); itr != end; ++itr)
diff --git a/src/Root.h b/src/Root.h
index 4cb77a79d..13e208b8d 100644
--- a/src/Root.h
+++ b/src/Root.h
@@ -99,6 +99,9 @@ public:
/// Saves all chunks in all worlds
void SaveAllChunks(void); // tolua_export
+ /// Reloads all the groups
+ void ReloadGroups(void); // tolua_export
+
/// Calls the callback for each player in all worlds
bool ForEachPlayer(cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
diff --git a/src/Scoreboard.cpp b/src/Scoreboard.cpp
index b2edd613b..61ecac5b7 100644
--- a/src/Scoreboard.cpp
+++ b/src/Scoreboard.cpp
@@ -197,8 +197,8 @@ cTeam::cTeam(const AString & a_Name, const AString & a_DisplayName,
const AString & a_Prefix, const AString & a_Suffix)
: m_AllowsFriendlyFire(true)
, m_CanSeeFriendlyInvisible(false)
- , m_Name(a_Name)
, m_DisplayName(a_DisplayName)
+ , m_Name(a_Name)
, m_Prefix(a_Prefix)
, m_Suffix(a_Suffix)
{}
diff --git a/src/Server.cpp b/src/Server.cpp
index ba2b46d55..ab1458da4 100644
--- a/src/Server.cpp
+++ b/src/Server.cpp
@@ -459,6 +459,17 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallbac
if (split[0] == "reload")
{
cPluginManager::Get()->ReloadPlugins();
+ cRoot::Get()->ReloadGroups();
+ return;
+ }
+ if (split[0] == "reloadplugins")
+ {
+ cPluginManager::Get()->ReloadPlugins();
+ return;
+ }
+ if (split[0] == "reloadgroups")
+ {
+ cRoot::Get()->ReloadGroups();
return;
}
diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp
new file mode 100644
index 000000000..5dba69455
--- /dev/null
+++ b/src/Simulator/IncrementalRedstoneSimulator.cpp
@@ -0,0 +1,1534 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "IncrementalRedstoneSimulator.h"
+#include "../BlockEntities/DropSpenserEntity.h"
+#include "../BlockEntities/NoteEntity.h"
+#include "../BlockEntities/CommandBlockEntity.h"
+#include "../Entities/TNTEntity.h"
+#include "../Blocks/BlockTorch.h"
+#include "../Blocks/BlockDoor.h"
+#include "../Piston.h"
+
+
+
+
+
+cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulator(cWorld & a_World)
+ : super(a_World)
+{
+}
+
+
+
+
+
+cIncrementalRedstoneSimulator::~cIncrementalRedstoneSimulator()
+{
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk)
+{
+ if ((a_Chunk == NULL) || !a_Chunk->IsValid())
+ {
+ return;
+ }
+ else if ((a_BlockY < 0) || (a_BlockY > cChunkDef::Height))
+ {
+ return;
+ }
+
+ int RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width;
+ int RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width;
+
+ BLOCKTYPE Block;
+ NIBBLETYPE Meta;
+ a_Chunk->GetBlockTypeMeta(RelX, a_BlockY, RelZ, Block, Meta);
+
+ // Every time a block is changed (AddBlock called), we want to go through all lists and check to see if the coordiantes stored within are still valid
+ // Checking only when a block is changed, as opposed to every tick, also improves performance
+
+ for (PoweredBlocksList::iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr)
+ {
+ if (!itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
+ {
+ continue;
+ }
+
+ if (!IsPotentialSource(Block))
+ {
+ LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from powered blocks list as it no longer connected to a source", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
+ m_PoweredBlocks.erase(itr);
+ break;
+ }
+ else if (
+ // Changeable sources
+ ((Block == E_BLOCK_REDSTONE_WIRE) && (Meta == 0)) ||
+ ((Block == E_BLOCK_LEVER) && !IsLeverOn(Meta)) ||
+ ((Block == E_BLOCK_DETECTOR_RAIL) && (Meta & 0x08) == 0) ||
+ (((Block == E_BLOCK_STONE_BUTTON) || (Block == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(Meta))) ||
+ (((Block == E_BLOCK_STONE_PRESSURE_PLATE) || (Block == E_BLOCK_WOODEN_PRESSURE_PLATE)) && (Meta == 0))
+ )
+ {
+ LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from powered blocks list due to present/past metadata mismatch", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
+ m_PoweredBlocks.erase(itr);
+ break;
+ }
+ else if (Block == E_BLOCK_DAYLIGHT_SENSOR)
+ {
+ if (!a_Chunk->IsLightValid())
+ {
+ m_World.QueueLightChunk(a_Chunk->GetPosX(), a_Chunk->GetPosZ());
+ break;
+ }
+ else
+ {
+ NIBBLETYPE SkyLight;
+ a_Chunk->UnboundedRelGetBlockSkyLight(RelX, itr->a_SourcePos.y + 1, RelZ, SkyLight);
+
+ if (a_Chunk->GetTimeAlteredLight(SkyLight) <= 8) // Could use SkyLight - m_World.GetSkyDarkness();
+ {
+ LOGD("cIncrementalRedstoneSimulator: Erased daylight sensor from powered blocks list due to insufficient light level");
+ m_PoweredBlocks.erase(itr);
+ break;
+ }
+ }
+ }
+ }
+
+ for (LinkedBlocksList::iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr)
+ {
+ if (itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
+ {
+ if (!IsPotentialSource(Block))
+ {
+ LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list as it is no longer connected to a source", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
+ m_LinkedPoweredBlocks.erase(itr);
+ break;
+ }
+ else if (
+ // Things that can send power through a block but which depends on meta
+ ((Block == E_BLOCK_REDSTONE_WIRE) && (Meta == 0)) ||
+ ((Block == E_BLOCK_LEVER) && !IsLeverOn(Meta)) ||
+ (((Block == E_BLOCK_STONE_BUTTON) || (Block == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(Meta)))
+ )
+ {
+ LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list due to present/past metadata mismatch", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
+ m_LinkedPoweredBlocks.erase(itr);
+ break;
+ }
+ }
+ else if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
+ {
+ if (!IsViableMiddleBlock(Block))
+ {
+ LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list as it is no longer powered through a valid middle block", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
+ m_LinkedPoweredBlocks.erase(itr);
+ break;
+ }
+ }
+ }
+
+ for (SimulatedPlayerToggleableList::iterator itr = m_SimulatedPlayerToggleableBlocks.begin(); itr != m_SimulatedPlayerToggleableBlocks.end(); ++itr)
+ {
+ if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
+ {
+ continue;
+ }
+
+ if (!IsAllowedBlock(Block))
+ {
+ LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from toggleable simulated list as it is no longer redstone", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
+ m_SimulatedPlayerToggleableBlocks.erase(itr);
+ break;
+ }
+ }
+
+ for (RepeatersDelayList::iterator itr = m_RepeatersDelayList.begin(); itr != m_RepeatersDelayList.end(); ++itr)
+ {
+ if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
+ {
+ continue;
+ }
+
+ if ((Block != E_BLOCK_REDSTONE_REPEATER_ON) && (Block != E_BLOCK_REDSTONE_REPEATER_OFF))
+ {
+ m_RepeatersDelayList.erase(itr);
+ break;
+ }
+ }
+
+ cRedstoneSimulatorChunkData & ChunkData = a_Chunk->GetRedstoneSimulatorData();
+ for (cRedstoneSimulatorChunkData::iterator itr = ChunkData.begin(); itr != ChunkData.end(); ++itr)
+ {
+ if ((itr->x == RelX) && (itr->y == a_BlockY) && (itr->z == RelZ)) // We are at an entry matching the current (changed) block
+ {
+ if (!IsAllowedBlock(Block))
+ {
+ itr->DataTwo = true; // The new blocktype is not redstone; it must be queued to be removed from this list
+ }
+ else
+ {
+ itr->Data = Block; // Update block information
+ }
+ return;
+ }
+ }
+
+ if (!IsAllowedBlock(Block))
+ {
+ return;
+ }
+
+ ChunkData.push_back(cCoordWithBlockAndBool(RelX, a_BlockY, RelZ, Block, false));
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk)
+{
+ // We still attempt to simulate all blocks in the chunk every tick, because of outside influence that needs to be taken into account
+ // For example, repeaters need to be ticked, pressure plates checked for entities, daylight sensor checked for light changes, etc.
+ // The easiest way to make this more efficient is probably just to reduce code within the handlers that put too much strain on server, like getting or setting blocks
+ // A marking dirty system might be a TODO for later on, perhaps
+
+ cRedstoneSimulatorChunkData & ChunkData = a_Chunk->GetRedstoneSimulatorData();
+ if (ChunkData.empty())
+ {
+ return;
+ }
+
+ int BaseX = a_Chunk->GetPosX() * cChunkDef::Width;
+ int BaseZ = a_Chunk->GetPosZ() * cChunkDef::Width;
+
+ for (cRedstoneSimulatorChunkData::iterator dataitr = ChunkData.begin(); dataitr != ChunkData.end();)
+ {
+ if (dataitr->DataTwo)
+ {
+ dataitr = ChunkData.erase(dataitr);
+ continue;
+ }
+
+ int a_X = BaseX + dataitr->x;
+ int a_Z = BaseZ + dataitr->z;
+ switch (dataitr->Data)
+ {
+ case E_BLOCK_BLOCK_OF_REDSTONE: HandleRedstoneBlock(a_X, dataitr->y, a_Z); break;
+ case E_BLOCK_LEVER: HandleRedstoneLever(a_X, dataitr->y, a_Z); break;
+ case E_BLOCK_TNT: HandleTNT(a_X, dataitr->y, a_Z); break;
+ case E_BLOCK_TRAPDOOR: HandleTrapdoor(a_X, dataitr->y, a_Z); break;
+ case E_BLOCK_REDSTONE_WIRE: HandleRedstoneWire(a_X, dataitr->y, a_Z); break;
+ case E_BLOCK_NOTE_BLOCK: HandleNoteBlock(a_X, dataitr->y, a_Z); break;
+ case E_BLOCK_DAYLIGHT_SENSOR: HandleDaylightSensor(a_X, dataitr->y, a_Z); break;
+ case E_BLOCK_COMMAND_BLOCK: HandleCommandBlock(a_X, dataitr->y, a_Z); break;
+
+ case E_BLOCK_REDSTONE_TORCH_OFF:
+ case E_BLOCK_REDSTONE_TORCH_ON:
+ {
+ HandleRedstoneTorch(a_X, dataitr->y, a_Z, dataitr->Data);
+ break;
+ }
+ case E_BLOCK_STONE_BUTTON:
+ case E_BLOCK_WOODEN_BUTTON:
+ {
+ HandleRedstoneButton(a_X, dataitr->y, a_Z, dataitr->Data);
+ break;
+ }
+ case E_BLOCK_REDSTONE_REPEATER_OFF:
+ case E_BLOCK_REDSTONE_REPEATER_ON:
+ {
+ HandleRedstoneRepeater(a_X, dataitr->y, a_Z, dataitr->Data);
+ break;
+ }
+ case E_BLOCK_PISTON:
+ case E_BLOCK_STICKY_PISTON:
+ {
+ HandlePiston(a_X, dataitr->y, a_Z);
+ break;
+ }
+ case E_BLOCK_REDSTONE_LAMP_OFF:
+ case E_BLOCK_REDSTONE_LAMP_ON:
+ {
+ HandleRedstoneLamp(a_X, dataitr->y, a_Z, dataitr->Data);
+ break;
+ }
+ case E_BLOCK_DISPENSER:
+ case E_BLOCK_DROPPER:
+ {
+ HandleDropSpenser(a_X, dataitr->y, a_Z);
+ break;
+ }
+ case E_BLOCK_WOODEN_DOOR:
+ case E_BLOCK_IRON_DOOR:
+ {
+ HandleDoor(a_X, dataitr->y, a_Z);
+ break;
+ }
+ case E_BLOCK_ACTIVATOR_RAIL:
+ case E_BLOCK_DETECTOR_RAIL:
+ case E_BLOCK_POWERED_RAIL:
+ {
+ HandleRail(a_X, dataitr->y, a_Z, dataitr->Data);
+ break;
+ }
+ case E_BLOCK_WOODEN_PRESSURE_PLATE:
+ case E_BLOCK_STONE_PRESSURE_PLATE:
+ {
+ HandlePressurePlate(a_X, dataitr->y, a_Z, dataitr->Data);
+ break;
+ }
+ }
+ ++dataitr;
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState)
+{
+ static const struct // Define which directions the torch can power
+ {
+ int x, y, z;
+ } gCrossCoords[] =
+ {
+ { 1, 0, 0},
+ {-1, 0, 0},
+ { 0, 0, 1},
+ { 0, 0, -1},
+ { 0, 1, 0},
+ } ;
+
+ if (a_MyState == E_BLOCK_REDSTONE_TORCH_ON)
+ {
+ // Check if the block the torch is on is powered
+ int X = a_BlockX; int Y = a_BlockY; int Z = a_BlockZ;
+ AddFaceDirection(X, Y, Z, cBlockTorchHandler::MetaDataToDirection(m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)), true); // Inverse true to get the block torch is on
+
+ if (AreCoordsDirectlyPowered(X, Y, Z))
+ {
+ // There was a match, torch goes off
+ m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_OFF, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ));
+ return;
+ }
+
+ // Torch still on, make all 4(X, Z) + 1(Y) sides powered
+ for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++)
+ {
+ BLOCKTYPE Type = m_World.GetBlock(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z);
+ if (i + 1 < ARRAYCOUNT(gCrossCoords)) // Sides of torch, not top (top is last)
+ {
+ if (
+ ((IsMechanism(Type)) || (Type == E_BLOCK_REDSTONE_WIRE)) && // Is it a mechanism or wire? Not block/other torch etc.
+ (!Vector3i(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z).Equals(Vector3i(X, Y, Z))) // CAN'T power block is that it is on
+ )
+ {
+ SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON);
+ }
+ }
+ else
+ {
+ // Top side, power whatever is there, including blocks
+ SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON);
+ // Power all blocks surrounding block above torch
+ SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YP, E_BLOCK_REDSTONE_TORCH_ON);
+ }
+ }
+
+ if (m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) != 0x5) // Is torch standing on ground? If NOT (i.e. on wall), power block beneath
+ {
+ BLOCKTYPE Type = m_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ);
+
+ if ((IsMechanism(Type)) || (Type == E_BLOCK_REDSTONE_WIRE)) // Still can't make a normal block powered though!
+ {
+ SetBlockPowered(a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON);
+ }
+ }
+ }
+ else
+ {
+ // Check if the block the torch is on is powered
+ int X = a_BlockX; int Y = a_BlockY; int Z = a_BlockZ;
+ AddFaceDirection(X, Y, Z, cBlockTorchHandler::MetaDataToDirection(m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)), true); // Inverse true to get the block torch is on
+
+ // See if off state torch can be turned on again
+ if (AreCoordsDirectlyPowered(X, Y, Z))
+ {
+ return; // Something matches, torch still powered
+ }
+
+ // Block torch on not powered, can be turned on again!
+ m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ));
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandleRedstoneBlock(int a_BlockX, int a_BlockY, int a_BlockZ)
+{
+ SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_BLOCK_OF_REDSTONE);
+ SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_BLOCK_OF_REDSTONE); // Set self as powered
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandleRedstoneLever(int a_BlockX, int a_BlockY, int a_BlockZ)
+{
+ if (IsLeverOn(m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)))
+ {
+ SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_LEVER);
+
+ SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_LEVER);
+ SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_LEVER);
+ SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, E_BLOCK_LEVER);
+ SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YP, E_BLOCK_LEVER);
+ SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_LEVER);
+ SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_LEVER);
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandleRedstoneButton(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType)
+{
+ if (IsButtonOn(m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)))
+ {
+ SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, a_BlockType);
+
+ SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, a_BlockType);
+ SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, a_BlockType);
+ SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, a_BlockType);
+ SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YP, a_BlockType);
+ SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, a_BlockType);
+ SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, a_BlockType);
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_BlockY, int a_BlockZ)
+{
+ static const struct // Define which directions the wire can receive power from
+ {
+ int x, y, z;
+ } gCrossCoords[] =
+ {
+ { 1, 0, 0}, /* Wires on same level start */
+ {-1, 0, 0},
+ { 0, 0, 1},
+ { 0, 0, -1}, /* Wires on same level stop */
+ { 1, 1, 0}, /* Wires one higher, surrounding self start */
+ {-1, 1, 0},
+ { 0, 1, 1},
+ { 0, 1, -1}, /* Wires one higher, surrounding self stop */
+ { 1,-1, 0}, /* Wires one lower, surrounding self start */
+ {-1,-1, 0},
+ { 0,-1, 1},
+ { 0,-1, -1}, /* Wires one lower, surrounding self stop */
+ } ;
+
+ static const struct // Define which directions the wire will check for repeater prescence
+ {
+ int x, y, z;
+ } gSideCoords[] =
+ {
+ { 1, 0, 0 },
+ {-1, 0, 0 },
+ { 0, 0, 1 },
+ { 0, 0,-1 },
+ { 0, 1, 0 },
+ };
+
+ // Check to see if directly beside a power source
+ if (IsWirePowered(a_BlockX, a_BlockY, a_BlockZ))
+ {
+ m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 15); // Maximum power
+ }
+ else
+ {
+ NIBBLETYPE MetaToSet = 0;
+ NIBBLETYPE MyMeta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
+ int TimesMetaSmaller = 0, TimesFoundAWire = 0;
+
+ for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through all directions to transfer or receive power
+ {
+ if ((i >= 4) && (i <= 7)) // If we are currently checking for wire surrounding ourself one block above...
+ {
+ if (g_BlockIsSolid[m_World.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ)]) // If there is something solid above us (wire cut off)...
+ {
+ continue; // We don't receive power from that wire
+ }
+ }
+ else if ((i >= 8) && (i <= 11)) // See above, but this is for wire below us
+ {
+ if (g_BlockIsSolid[m_World.GetBlock(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y + 1, a_BlockZ + gCrossCoords[i].z)])
+ {
+ continue;
+ }
+ }
+
+ BLOCKTYPE SurroundType;
+ NIBBLETYPE SurroundMeta;
+ m_World.GetBlockTypeMeta(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, SurroundType, SurroundMeta);
+
+ if (SurroundType == E_BLOCK_REDSTONE_WIRE)
+ {
+ TimesFoundAWire++;
+
+ if (SurroundMeta > 1) // Wires of power 1 or 0 cannot transfer power TO ME, don't bother checking
+ {
+ // Does surrounding wire have a higher power level than self?
+ // >= to fix a bug where wires bordering each other with the same power level will appear (in terms of meta) to power each other, when they aren't actually in the powered list
+ if (SurroundMeta >= MyMeta)
+ {
+ MetaToSet = SurroundMeta - 1; // To improve performance
+ }
+ }
+
+ if (SurroundMeta < MyMeta) // Go through all surroundings to see if self power is larger than everyone else's
+ {
+ TimesMetaSmaller++;
+ }
+ }
+ }
+
+ if (TimesMetaSmaller == TimesFoundAWire)
+ {
+ // All surrounding metas were smaller - self must have been a wire that was
+ // transferring power to other wires around.
+ // However, self not directly powered anymore, so source must have been removed,
+ // therefore, self must be set to meta zero
+ m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, 0); // SetMeta & WakeUpSims doesn't seem to work here, so SetBlock
+ return; // No need to process block power sets because self not powered
+ }
+ else
+ {
+ m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, MetaToSet);
+ }
+ }
+
+ if (m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) != 0) // A powered wire
+ {
+ for (size_t i = 0; i < ARRAYCOUNT(gSideCoords); i++) // Look for repeaters immediately surrounding self and try to power them
+ {
+ if (m_World.GetBlock(a_BlockX + gSideCoords[i].x, a_BlockY + gSideCoords[i].y, a_BlockZ + gSideCoords[i].z) == E_BLOCK_REDSTONE_REPEATER_OFF)
+ {
+ SetBlockPowered(a_BlockX + gSideCoords[i].x, a_BlockY + gSideCoords[i].y, a_BlockZ + gSideCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
+ }
+ }
+
+ // Wire still powered, power blocks beneath
+ SetBlockPowered(a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
+ SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, E_BLOCK_REDSTONE_WIRE);
+
+ switch (GetWireDirection(a_BlockX, a_BlockY, a_BlockZ))
+ {
+ case REDSTONE_NONE:
+ {
+ SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
+
+ SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_REDSTONE_WIRE);
+ SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_REDSTONE_WIRE);
+ SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, E_BLOCK_REDSTONE_WIRE);
+ SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YP, E_BLOCK_REDSTONE_WIRE);
+ SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_REDSTONE_WIRE);
+ SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_REDSTONE_WIRE);
+ break;
+ }
+ case REDSTONE_X_POS:
+ {
+ SetBlockPowered(a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
+ SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_REDSTONE_WIRE);
+ break;
+ }
+ case REDSTONE_X_NEG:
+ {
+ SetBlockPowered(a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
+ SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_REDSTONE_WIRE);
+ break;
+ }
+ case REDSTONE_Z_POS:
+ {
+ SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
+ SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_REDSTONE_WIRE);
+ break;
+ }
+ case REDSTONE_Z_NEG:
+ {
+ SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
+ SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_REDSTONE_WIRE);
+ break;
+ }
+ }
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState)
+{
+ NIBBLETYPE a_Meta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
+
+ bool IsOn = ((a_MyState == E_BLOCK_REDSTONE_REPEATER_ON) ? true : false); // Cache if repeater is on
+ bool IsSelfPowered = IsRepeaterPowered(a_BlockX, a_BlockY, a_BlockZ, a_Meta & 0x3); // Cache if repeater is pwoered
+
+ if (IsSelfPowered && !IsOn) // Queue a power change if I am receiving power but not on
+ {
+ QueueRepeaterPowerChange(a_BlockX, a_BlockY, a_BlockZ, a_Meta, 0, true);
+ }
+ else if (!IsSelfPowered && IsOn) // Queue a power change if I am not receiving power but on
+ {
+ QueueRepeaterPowerChange(a_BlockX, a_BlockY, a_BlockZ, a_Meta, 0, false);
+ }
+
+ for (RepeatersDelayList::iterator itr = m_RepeatersDelayList.begin(); itr != m_RepeatersDelayList.end(); ++itr)
+ {
+ if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
+ {
+ continue;
+ }
+
+ if (itr->a_ElapsedTicks >= itr->a_DelayTicks) // Has the elapsed ticks reached the target ticks?
+ {
+ if (itr->ShouldPowerOn)
+ {
+ if (!IsOn)
+ {
+ m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON, a_Meta); // For performance
+ }
+
+ switch (a_Meta & 0x3) // We only want the direction (bottom) bits
+ {
+ case 0x0:
+ {
+ SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON);
+ SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_REDSTONE_REPEATER_ON);
+ break;
+ }
+ case 0x1:
+ {
+ SetBlockPowered(a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON);
+ SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_REDSTONE_REPEATER_ON);
+ break;
+ }
+ case 0x2:
+ {
+ SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON);
+ SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_REDSTONE_REPEATER_ON);
+ break;
+ }
+ case 0x3:
+ {
+ SetBlockPowered(a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON);
+ SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_REDSTONE_REPEATER_ON);
+ break;
+ }
+ }
+
+ // Removal of the data entry will be handled in SimChunk - we still want to continue trying to power blocks, even if our delay time has reached
+ // Otherwise, the power state of blocks in front won't update after we have powered on
+ return;
+ }
+ else
+ {
+ if (IsOn)
+ {
+ m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_OFF, a_Meta);
+ }
+ m_RepeatersDelayList.erase(itr); // We can remove off repeaters which don't need further updating
+ return;
+ }
+ }
+ else
+ {
+ // Apparently, incrementing ticks only works reliably here, and not in SimChunk;
+ // With a world with lots of redstone, the repeaters simply do not delay
+ // I am confounded to say why. Perhaps optimisation failure.
+ LOGD("Incremented a repeater @ {%i %i %i} | Elapsed ticks: %i | Target delay: %i", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z, itr->a_ElapsedTicks, itr->a_DelayTicks);
+ itr->a_ElapsedTicks++;
+ }
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandlePiston(int a_BlockX, int a_BlockY, int a_BlockZ)
+{
+ cPiston Piston(&m_World);
+ if (IsPistonPowered(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x7)) // We only want the bottom three bits (4th controls extended-ness)
+ {
+ Piston.ExtendPiston(a_BlockX, a_BlockY, a_BlockZ);
+ }
+ else
+ {
+ Piston.RetractPiston(a_BlockX, a_BlockY, a_BlockZ);
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandleDropSpenser(int a_BlockX, int a_BlockY, int a_BlockZ)
+{
+ class cSetPowerToDropSpenser :
+ public cDropSpenserCallback
+ {
+ bool m_IsPowered;
+ public:
+ cSetPowerToDropSpenser(bool a_IsPowered) : m_IsPowered(a_IsPowered) {}
+
+ virtual bool Item(cDropSpenserEntity * a_DropSpenser) override
+ {
+ a_DropSpenser->SetRedstonePower(m_IsPowered);
+ return false;
+ }
+ } DrSpSP (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ));
+
+ m_World.DoWithDropSpenserAt(a_BlockX, a_BlockY, a_BlockZ, DrSpSP);
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandleRedstoneLamp(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState)
+{
+ if (a_MyState == E_BLOCK_REDSTONE_LAMP_OFF)
+ {
+ if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ))
+ {
+ m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_LAMP_ON, 0);
+ }
+ }
+ else
+ {
+ if (!AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ))
+ {
+ m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_LAMP_OFF, 0);
+ }
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandleTNT(int a_BlockX, int a_BlockY, int a_BlockZ)
+{
+ if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ))
+ {
+ m_World.BroadcastSoundEffect("random.fuse", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.6f);
+ m_World.SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, 4); // 4 seconds to boom
+ m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandleDoor(int a_BlockX, int a_BlockY, int a_BlockZ)
+{
+ if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ))
+ {
+ if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, true))
+ {
+ cChunkInterface ChunkInterface(m_World.GetChunkMap());
+ cBlockDoorHandler::ChangeDoor(ChunkInterface, a_BlockX, a_BlockY, a_BlockZ);
+ SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, true);
+ }
+ }
+ else
+ {
+ if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, false))
+ {
+ cChunkInterface ChunkInterface(m_World.GetChunkMap());
+ cBlockDoorHandler::ChangeDoor(ChunkInterface, a_BlockX, a_BlockY, a_BlockZ);
+ SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, false);
+ }
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandleCommandBlock(int a_BlockX, int a_BlockY, int a_BlockZ)
+{
+ class cSetPowerToCommandBlock :
+ public cCommandBlockCallback
+ {
+ bool m_IsPowered;
+ public:
+ cSetPowerToCommandBlock(bool a_IsPowered) : m_IsPowered(a_IsPowered) {}
+
+ virtual bool Item(cCommandBlockEntity * a_CommandBlock) override
+ {
+ a_CommandBlock->SetRedstonePower(m_IsPowered);
+ return false;
+ }
+ } CmdBlockSP (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ));
+
+ m_World.DoWithCommandBlockAt(a_BlockX, a_BlockY, a_BlockZ, CmdBlockSP);
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandleRail(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType)
+{
+ switch (a_MyType)
+ {
+ case E_BLOCK_DETECTOR_RAIL:
+ {
+ if ((m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x08) == 0x08)
+ {
+ SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, a_MyType);
+ }
+ break;
+ }
+ case E_BLOCK_ACTIVATOR_RAIL:
+ case E_BLOCK_POWERED_RAIL:
+ {
+ if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ))
+ {
+ m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) | 0x08);
+ }
+ else
+ {
+ m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x07);
+ }
+ break;
+ }
+ default: LOGD("Unhandled type of rail in %s", __FUNCTION__);
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandleTrapdoor(int a_BlockX, int a_BlockY, int a_BlockZ)
+{
+ if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ))
+ {
+ if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, true))
+ {
+ m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) | 0x4);
+ SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, true);
+ }
+ }
+ else
+ {
+ if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, false))
+ {
+ m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0xB); // Take into account that the fourth bit is needed for trapdoors too
+ SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, false);
+ }
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandleNoteBlock(int a_BlockX, int a_BlockY, int a_BlockZ)
+{
+ bool m_bAreCoordsPowered = AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ);
+
+ if (m_bAreCoordsPowered)
+ {
+ if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, true))
+ {
+ class cSetPowerToNoteBlock :
+ public cNoteBlockCallback
+ {
+ bool m_IsPowered;
+ public:
+ cSetPowerToNoteBlock(bool a_IsPowered) : m_IsPowered(a_IsPowered) {}
+
+ virtual bool Item(cNoteEntity * a_NoteBlock) override
+ {
+ if (m_IsPowered)
+ {
+ a_NoteBlock->MakeSound();
+ }
+ return false;
+ }
+ } NoteBlockSP(m_bAreCoordsPowered);
+
+ m_World.DoWithNoteBlockAt(a_BlockX, a_BlockY, a_BlockZ, NoteBlockSP);
+ SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, true);
+ }
+ }
+ else
+ {
+ if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, false))
+ {
+ SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, false);
+ }
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandleDaylightSensor(int a_BlockX, int a_BlockY, int a_BlockZ)
+{
+ int a_ChunkX, a_ChunkZ;
+ cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, a_ChunkX, a_ChunkZ);
+
+ if (!m_World.IsChunkLighted(a_ChunkX, a_ChunkZ))
+ {
+ m_World.QueueLightChunk(a_ChunkX, a_ChunkZ);
+ }
+ else
+ {
+ NIBBLETYPE SkyLight = m_World.GetBlockSkyLight(a_BlockX, a_BlockY + 1, a_BlockZ) - m_World.GetSkyDarkness();
+ if (SkyLight > 8)
+ {
+ SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_DAYLIGHT_SENSOR);
+ }
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType)
+{
+ switch (a_MyType)
+ {
+ case E_BLOCK_STONE_PRESSURE_PLATE:
+ {
+ // MCS feature - stone pressure plates can only be triggered by players :D
+ cPlayer * a_Player = m_World.FindClosestPlayer(Vector3f(a_BlockX + 0.5f, (float)a_BlockY, a_BlockZ + 0.5f), 0.5f, false);
+
+ if (a_Player != NULL)
+ {
+ m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x1);
+ SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_STONE_PRESSURE_PLATE);
+ }
+ else
+ {
+ m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x0);
+ m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ);
+ }
+ break;
+ }
+ case E_BLOCK_WOODEN_PRESSURE_PLATE:
+ {
+ class cWoodenPressurePlateCallback :
+ public cEntityCallback
+ {
+ public:
+ cWoodenPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
+ m_Entity(NULL),
+ m_World(a_World),
+ m_X(a_BlockX),
+ m_Y(a_BlockY),
+ m_Z(a_BlockZ)
+ {
+ }
+
+ virtual bool Item(cEntity * a_Entity) override
+ {
+ Vector3f EntityPos = a_Entity->GetPosition();
+ Vector3f BlockPos(m_X + 0.5f, (float)m_Y, m_Z + 0.5f);
+ float Distance = (EntityPos - BlockPos).Length();
+
+ if (Distance < 0.5)
+ {
+ m_Entity = a_Entity;
+ return true; // Break out, we only need to know for wooden plates that at least one entity is on top
+ }
+ return false;
+ }
+
+ bool FoundEntity(void) const
+ {
+ return m_Entity != NULL;
+ }
+
+ protected:
+ cEntity * m_Entity;
+ cWorld * m_World;
+
+ int m_X;
+ int m_Y;
+ int m_Z;
+ } ;
+
+ cWoodenPressurePlateCallback WoodenPressurePlateCallback(a_BlockX, a_BlockY, a_BlockZ, &m_World);
+ m_World.ForEachEntity(WoodenPressurePlateCallback);
+
+ if (WoodenPressurePlateCallback.FoundEntity())
+ {
+ m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x1);
+ SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_WOODEN_PRESSURE_PLATE);
+ }
+ else
+ {
+ m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x0);
+ m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ);
+ }
+ break;
+ }
+ default:
+ LOGD("Unimplemented pressure plate type %s in cRedstoneSimulator", ItemToFullString(a_MyType).c_str());
+ break;
+ }
+}
+
+
+
+
+
+bool cIncrementalRedstoneSimulator::AreCoordsDirectlyPowered(int a_BlockX, int a_BlockY, int a_BlockZ)
+{
+ for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr) // Check powered list
+ {
+ if (itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+
+
+bool cIncrementalRedstoneSimulator::AreCoordsLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ)
+{
+ for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr) // Check linked powered list
+ {
+ if (itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+
+
+bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta)
+{
+ // Repeaters cannot be powered by any face except their back; verify that this is true for a source
+
+ for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr)
+ {
+ if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; }
+
+ switch (a_Meta)
+ {
+ case 0x0:
+ {
+ // Flip the coords to check the back of the repeater
+ if (itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ + 1))) { return true; }
+ break;
+ }
+ case 0x1:
+ {
+ if (itr->a_SourcePos.Equals(Vector3i(a_BlockX - 1, a_BlockY, a_BlockZ))) { return true; }
+ break;
+ }
+ case 0x2:
+ {
+ if (itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ - 1))) { return true; }
+ break;
+ }
+ case 0x3:
+ {
+ if (itr->a_SourcePos.Equals(Vector3i(a_BlockX + 1, a_BlockY, a_BlockZ))) { return true; }
+ break;
+ }
+ }
+ }
+
+ for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr)
+ {
+ if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; }
+
+ switch (a_Meta)
+ {
+ case 0x0:
+ {
+ if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ + 1))) { return true; }
+ break;
+ }
+ case 0x1:
+ {
+ if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX - 1, a_BlockY, a_BlockZ))) { return true; }
+ break;
+ }
+ case 0x2:
+ {
+ if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ - 1))) { return true; }
+ break;
+ }
+ case 0x3:
+ {
+ if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX + 1, a_BlockY, a_BlockZ))) { return true; }
+ break;
+ }
+ }
+ }
+ return false; // Couldn't find power source behind repeater
+}
+
+
+
+
+bool cIncrementalRedstoneSimulator::IsPistonPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta)
+{
+ // Pistons cannot be powered through their front face; this function verifies that a source meets this requirement
+
+ int OldX = a_BlockX, OldY = a_BlockY, OldZ = a_BlockZ;
+ eBlockFace Face = cPiston::MetaDataToDirection(a_Meta);
+
+ for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr)
+ {
+ if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; }
+
+ AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, Face);
+
+ if (!itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
+ {
+ return true;
+ }
+
+ a_BlockX = OldX;
+ a_BlockY = OldY;
+ a_BlockZ = OldZ;
+ }
+
+ for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr)
+ {
+ if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; }
+
+ AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, Face);
+
+ if (!itr->a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
+ {
+ return true;
+ }
+
+ a_BlockX = OldX;
+ a_BlockY = OldY;
+ a_BlockZ = OldZ;
+ }
+ return false; // Source was in front of the piston's front face
+}
+
+
+
+
+bool cIncrementalRedstoneSimulator::IsWirePowered(int a_BlockX, int a_BlockY, int a_BlockZ)
+{
+ for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr)
+ {
+ if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; }
+
+ if (m_World.GetBlock(itr->a_SourcePos) != E_BLOCK_REDSTONE_WIRE)
+ {
+ return true;
+ }
+ }
+
+ for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr)
+ {
+ if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; }
+
+ if (m_World.GetBlock(itr->a_SourcePos) != E_BLOCK_REDSTONE_WIRE)
+ {
+ return true;
+ }
+ }
+ return false; // Source was in front of the piston's front face
+}
+
+
+
+
+
+bool cIncrementalRedstoneSimulator::AreCoordsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool IsCurrentStatePowered)
+{
+ for (SimulatedPlayerToggleableList::const_iterator itr = m_SimulatedPlayerToggleableBlocks.begin(); itr != m_SimulatedPlayerToggleableBlocks.end(); ++itr)
+ {
+ if (itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
+ {
+ if (itr->WasLastStatePowered != IsCurrentStatePowered) // Was the last power state different to the current?
+ {
+ return false; // It was, coordinates are no longer simulated
+ }
+ else
+ {
+ return true; // It wasn't, don't resimulate block, and allow players to toggle
+ }
+ }
+ }
+ return false; // Block wasn't even in the list, not simulated
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Direction, BLOCKTYPE a_SourceType)
+{
+ switch (a_Direction)
+ {
+ case BLOCK_FACE_XM:
+ {
+ BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ);
+
+ SetBlockLinkedPowered(a_BlockX - 2, a_BlockY, a_BlockZ, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+ SetBlockLinkedPowered(a_BlockX - 1, a_BlockY + 1, a_BlockZ, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+ SetBlockLinkedPowered(a_BlockX - 1, a_BlockY - 1, a_BlockZ, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+ SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ + 1, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+ SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ - 1, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+
+ break;
+ }
+ case BLOCK_FACE_XP:
+ {
+ BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ);
+
+ SetBlockLinkedPowered(a_BlockX + 2, a_BlockY, a_BlockZ, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+ SetBlockLinkedPowered(a_BlockX + 1, a_BlockY + 1, a_BlockZ, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+ SetBlockLinkedPowered(a_BlockX + 1, a_BlockY - 1, a_BlockZ, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+ SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ + 1, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+ SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ - 1, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+
+ break;
+ }
+ case BLOCK_FACE_YM:
+ {
+ BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ);
+
+ SetBlockLinkedPowered(a_BlockX, a_BlockY - 2, a_BlockZ, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+ SetBlockLinkedPowered(a_BlockX + 1, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+ SetBlockLinkedPowered(a_BlockX - 1, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+ SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ + 1, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+ SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ - 1, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+
+ break;
+ }
+ case BLOCK_FACE_YP:
+ {
+ BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ);
+
+ SetBlockLinkedPowered(a_BlockX, a_BlockY + 2, a_BlockZ, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+ SetBlockLinkedPowered(a_BlockX + 1, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+ SetBlockLinkedPowered(a_BlockX - 1, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+ SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ + 1, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+ SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ - 1, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+
+ break;
+ }
+ case BLOCK_FACE_ZM:
+ {
+ BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ - 1);
+
+ SetBlockLinkedPowered(a_BlockX, a_BlockY, a_BlockZ - 2, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+ SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+ SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+ SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+ SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+
+ break;
+ }
+ case BLOCK_FACE_ZP:
+ {
+ BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1);
+
+ SetBlockLinkedPowered(a_BlockX, a_BlockY, a_BlockZ + 2, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+ SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+ SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+ SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+ SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
+
+ break;
+ }
+ default:
+ {
+ ASSERT(!"Unhandled face direction when attempting to set blocks as linked powered!"); // Zombies, that wasn't supposed to happen...
+ break;
+ }
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::SetAllDirsAsPowered(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_SourceBlock)
+{
+ static const struct
+ {
+ int x, y, z;
+ } gCrossCoords[] =
+ {
+ { 1, 0, 0 },
+ {-1, 0, 0 },
+ { 0, 0, 1 },
+ { 0, 0,-1 },
+ { 0, 1, 0 },
+ { 0,-1, 0 }
+ };
+
+ for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through struct to power all directions
+ {
+ SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, a_SourceBlock);
+ }
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::SetBlockPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock)
+{
+ BLOCKTYPE Block = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ);
+ if (Block == E_BLOCK_AIR)
+ {
+ // Don't set air, fixes some bugs (wires powering themselves)
+ return;
+ }
+
+ for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr) // Check powered list
+ {
+ if (
+ itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)) &&
+ itr->a_SourcePos.Equals(Vector3i(a_SourceX, a_SourceY, a_SourceZ))
+ )
+ {
+ // Check for duplicates
+ return;
+ }
+ }
+
+ sPoweredBlocks RC;
+ RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ);
+ RC.a_SourcePos = Vector3i(a_SourceX, a_SourceY, a_SourceZ);
+ m_PoweredBlocks.push_back(RC);
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::SetBlockLinkedPowered(
+ int a_BlockX, int a_BlockY, int a_BlockZ,
+ int a_MiddleX, int a_MiddleY, int a_MiddleZ,
+ int a_SourceX, int a_SourceY, int a_SourceZ,
+ BLOCKTYPE a_SourceBlock, BLOCKTYPE a_MiddleBlock
+)
+{
+ BLOCKTYPE DestBlock = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ);
+ if (DestBlock == E_BLOCK_AIR)
+ {
+ // Don't set air, fixes some bugs (wires powering themselves)
+ return;
+ }
+ if (!IsViableMiddleBlock(a_MiddleBlock))
+ {
+ return;
+ }
+
+ for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr) // Check linked powered list
+ {
+ if (
+ itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)) &&
+ itr->a_MiddlePos.Equals(Vector3i(a_MiddleX, a_MiddleY, a_MiddleZ)) &&
+ itr->a_SourcePos.Equals(Vector3i(a_SourceX, a_SourceY, a_SourceZ))
+ )
+ {
+ // Check for duplicates
+ return;
+ }
+ }
+
+ sLinkedPoweredBlocks RC;
+ RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ);
+ RC.a_MiddlePos = Vector3i(a_MiddleX, a_MiddleY, a_MiddleZ);
+ RC.a_SourcePos = Vector3i(a_SourceX, a_SourceY, a_SourceZ);
+ m_LinkedPoweredBlocks.push_back(RC);
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::SetPlayerToggleableBlockAsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool WasLastStatePowered)
+{
+ for (SimulatedPlayerToggleableList::iterator itr = m_SimulatedPlayerToggleableBlocks.begin(); itr != m_SimulatedPlayerToggleableBlocks.end(); ++itr)
+ {
+ if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
+ {
+ continue;
+ }
+
+ if (itr->WasLastStatePowered != WasLastStatePowered)
+ {
+ // If power states different, update listing
+ itr->WasLastStatePowered = WasLastStatePowered;
+ return;
+ }
+ else
+ {
+ // If states the same, just ignore
+ return;
+ }
+ }
+
+ // We have arrive here; no block must be in list - add one
+ sSimulatedPlayerToggleableList RC;
+ RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ);
+ RC.WasLastStatePowered = WasLastStatePowered;
+ m_SimulatedPlayerToggleableBlocks.push_back(RC);
+}
+
+
+
+
+
+void cIncrementalRedstoneSimulator::QueueRepeaterPowerChange(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta, short a_ElapsedTicks, bool ShouldPowerOn)
+{
+ for (RepeatersDelayList::iterator itr = m_RepeatersDelayList.begin(); itr != m_RepeatersDelayList.end(); ++itr)
+ {
+ if (itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
+ {
+ if (ShouldPowerOn == itr->ShouldPowerOn) // We are queued already for the same thing, don't replace entry
+ {
+ return;
+ }
+
+ // Already in here (normal to allow repeater to continue on powering and updating blocks in front) - just update info and quit
+ itr->a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + (ShouldPowerOn ? 1 : 0)) * 2; // See below for description
+ itr->a_ElapsedTicks = 0;
+ itr->ShouldPowerOn = ShouldPowerOn;
+ return;
+ }
+ }
+
+ // Self not in list, add self to list
+ sRepeatersDelayList RC;
+ RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ);
+
+ // Gets the top two bits (delay time), shifts them into the lower two bits, and adds one (meta 0 = 1 tick; 1 = 2 etc.)
+ // * 2 because apparently, MCS ticks are way faster than vanilla ticks, so repeater aren't noticeably delayed
+ // We don't +1 when powering off because everything seems to already delay a tick when powering off, why? No idea :P
+ RC.a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + (ShouldPowerOn ? 1 : 0)) * 2;
+
+
+ RC.a_ElapsedTicks = 0;
+ RC.ShouldPowerOn = ShouldPowerOn;
+ m_RepeatersDelayList.push_back(RC);
+ return;
+}
+
+
+
+
+
+cIncrementalRedstoneSimulator::eRedstoneDirection cIncrementalRedstoneSimulator::GetWireDirection(int a_BlockX, int a_BlockY, int a_BlockZ)
+{
+ int Dir = REDSTONE_NONE;
+
+ BLOCKTYPE NegX = m_World.GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ);
+ if (IsPotentialSource(NegX))
+ {
+ Dir |= (REDSTONE_X_POS);
+ }
+
+ BLOCKTYPE PosX = m_World.GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ);
+ if (IsPotentialSource(PosX))
+ {
+ Dir |= (REDSTONE_X_NEG);
+ }
+
+ BLOCKTYPE NegZ = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ - 1);
+ if (IsPotentialSource(NegZ))
+ {
+ if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner
+ {
+ Dir ^= REDSTONE_X_POS;
+ Dir |= REDSTONE_X_NEG;
+ }
+ if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner
+ {
+ Dir ^= REDSTONE_X_NEG;
+ Dir |= REDSTONE_X_POS;
+ }
+ Dir |= REDSTONE_Z_POS;
+ }
+
+ BLOCKTYPE PosZ = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1);
+ if (IsPotentialSource(PosZ))
+ {
+ if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner
+ {
+ Dir ^= REDSTONE_X_POS;
+ Dir |= REDSTONE_X_NEG;
+ }
+ if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner
+ {
+ Dir ^= REDSTONE_X_NEG;
+ Dir |= REDSTONE_X_POS;
+ }
+ Dir |= REDSTONE_Z_NEG;
+ }
+ return (eRedstoneDirection)Dir;
+}
+
+
+
+
+
+bool cIncrementalRedstoneSimulator::IsLeverOn(NIBBLETYPE a_BlockMeta)
+{
+ // Extract the ON bit from metadata and return if true if it is set:
+ return ((a_BlockMeta & 0x8) == 0x8);
+}
+
+
+
+
+
+bool cIncrementalRedstoneSimulator::IsButtonOn(NIBBLETYPE a_BlockMeta)
+{
+ return IsLeverOn(a_BlockMeta);
+}
+
+
+
+
diff --git a/src/Simulator/IncrementalRedstoneSimulator.h b/src/Simulator/IncrementalRedstoneSimulator.h
new file mode 100644
index 000000000..3397e143c
--- /dev/null
+++ b/src/Simulator/IncrementalRedstoneSimulator.h
@@ -0,0 +1,263 @@
+
+#pragma once
+
+#include "RedstoneSimulator.h"
+
+/// Per-chunk data for the simulator, specified individual chunks to simulate; 'Data' is not used
+typedef cCoordWithBlockAndBoolVector cRedstoneSimulatorChunkData;
+
+
+
+
+
+class cIncrementalRedstoneSimulator :
+ public cRedstoneSimulator
+{
+ typedef cRedstoneSimulator super;
+public:
+
+ cIncrementalRedstoneSimulator(cWorld & a_World);
+ ~cIncrementalRedstoneSimulator();
+
+ virtual void Simulate(float a_Dt) override { UNUSED(a_Dt);} // not used
+ virtual void SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) override;
+ virtual bool IsAllowedBlock( BLOCKTYPE a_BlockType ) override { return IsRedstone(a_BlockType); }
+
+ enum eRedstoneDirection
+ {
+ REDSTONE_NONE = 0,
+ REDSTONE_X_POS = 0x1,
+ REDSTONE_X_NEG = 0x2,
+ REDSTONE_Z_POS = 0x4,
+ REDSTONE_Z_NEG = 0x8,
+ };
+ eRedstoneDirection GetWireDirection(int a_BlockX, int a_BlockY, int a_BlockZ);
+
+private:
+
+ struct sPoweredBlocks // Define structure of the directly powered blocks list
+ {
+ Vector3i a_BlockPos; // Position of powered block
+ Vector3i a_SourcePos; // Position of source powering the block at a_BlockPos
+ };
+
+ struct sLinkedPoweredBlocks // Define structure of the indirectly powered blocks list (i.e. repeaters powering through a block to the block at the other side)
+ {
+ Vector3i a_BlockPos;
+ Vector3i a_MiddlePos;
+ Vector3i a_SourcePos;
+ };
+
+ struct sSimulatedPlayerToggleableList
+ {
+ Vector3i a_BlockPos;
+ bool WasLastStatePowered;
+ };
+
+ struct sRepeatersDelayList
+ {
+ Vector3i a_BlockPos;
+ short a_DelayTicks;
+ short a_ElapsedTicks;
+ bool ShouldPowerOn;
+ };
+
+ typedef std::vector <sPoweredBlocks> PoweredBlocksList;
+ typedef std::vector <sLinkedPoweredBlocks> LinkedBlocksList;
+ typedef std::vector <sSimulatedPlayerToggleableList> SimulatedPlayerToggleableList;
+ typedef std::vector <sRepeatersDelayList> RepeatersDelayList;
+
+ PoweredBlocksList m_PoweredBlocks;
+ LinkedBlocksList m_LinkedPoweredBlocks;
+ SimulatedPlayerToggleableList m_SimulatedPlayerToggleableBlocks;
+ RepeatersDelayList m_RepeatersDelayList;
+
+ virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override;
+
+ // We want a_MyState for devices needing a full FastSetBlock (as opposed to meta) because with our simulation model, we cannot keep setting the block if it is already set correctly
+ // In addition to being non-performant, it would stop the player from actually breaking said device
+
+ /* ====== SOURCES ====== */
+ /** Handles the redstone torch */
+ void HandleRedstoneTorch(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState);
+ /** Handles the redstone block */
+ void HandleRedstoneBlock(int a_BlockX, int a_BlockY, int a_BlockZ);
+ /** Handles levers */
+ void HandleRedstoneLever(int a_BlockX, int a_BlockY, int a_BlockZ);
+ /** Handles buttons */
+ void HandleRedstoneButton(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType);
+ /** Handles daylight sensors */
+ void HandleDaylightSensor(int a_BlockX, int a_BlockY, int a_BlockZ);
+ /** Handles pressure plates */
+ void HandlePressurePlate(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType);
+ /* ==================== */
+
+ /* ====== CARRIERS ====== */
+ /** Handles redstone wire */
+ void HandleRedstoneWire(int a_BlockX, int a_BlockY, int a_BlockZ);
+ /** Handles repeaters */
+ void HandleRedstoneRepeater(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState);
+ /* ====================== */
+
+ /* ====== DEVICES ====== */
+ /** Handles pistons */
+ void HandlePiston(int a_BlockX, int a_BlockY, int a_BlockZ);
+ /** Handles dispensers and droppers */
+ void HandleDropSpenser(int a_BlockX, int a_BlockY, int a_BlockZ);
+ /** Handles TNT (exploding) */
+ void HandleTNT(int a_BlockX, int a_BlockY, int a_BlockZ);
+ /** Handles redstone lamps */
+ void HandleRedstoneLamp(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState);
+ /** Handles doords */
+ void HandleDoor(int a_BlockX, int a_BlockY, int a_BlockZ);
+ /** Handles command blocks */
+ void HandleCommandBlock(int a_BlockX, int a_BlockY, int a_BlockZ);
+ /** Handles activator, detector, and powered rails */
+ void HandleRail(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType);
+ /** Handles trapdoors */
+ void HandleTrapdoor(int a_BlockX, int a_BlockY, int a_BlockZ);
+ /** Handles noteblocks */
+ void HandleNoteBlock(int a_BlockX, int a_BlockY, int a_BlockZ);
+ /* ===================== */
+
+ /* ====== Helper functions ====== */
+ /** Marks a block as powered */
+ void SetBlockPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock);
+ /** Marks a block as being powered through another block */
+ void SetBlockLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_MiddleX, int a_MiddleY, int a_MiddleZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock, BLOCKTYPE a_MiddeBlock);
+ /** Marks a block as simulated, who should not be simulated further unless their power state changes, to accomodate a player manually toggling the block without triggering the simulator toggling it back */
+ void SetPlayerToggleableBlockAsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool WasLastStatePowered);
+ /** Marks the second block in a direction as linked powered */
+ void SetDirectionLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Direction, BLOCKTYPE a_SourceBlock);
+ /** Marks all blocks immediately surrounding a coordinate as powered */
+ void SetAllDirsAsPowered(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_SourceBlock);
+ /** Queues a repeater to be powered or unpowered */
+ void QueueRepeaterPowerChange(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta, short a_ElapsedTicks, bool ShouldPowerOn);
+
+ /** Returns if a coordinate is powered or linked powered */
+ bool AreCoordsPowered(int a_BlockX, int a_BlockY, int a_BlockZ) { return AreCoordsDirectlyPowered(a_BlockX, a_BlockY, a_BlockZ) || AreCoordsLinkedPowered(a_BlockX, a_BlockY, a_BlockZ); }
+ /** Returns if a coordinate is in the directly powered blocks list */
+ bool AreCoordsDirectlyPowered(int a_BlockX, int a_BlockY, int a_BlockZ);
+ /** Returns if a coordinate is in the indirectly powered blocks list */
+ bool AreCoordsLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ);
+ /** Returns if a coordinate was marked as simulated (for blocks toggleable by players) */
+ bool AreCoordsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool IsCurrentStatePowered);
+ /** Returns if a repeater is powered */
+ bool IsRepeaterPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta);
+ /** Returns if a piston is powered */
+ bool IsPistonPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta);
+ /** Returns if a wire is powered
+ The only diffence between this and a normal AreCoordsPowered is that this function checks for a wire powering another wire
+ */
+ bool IsWirePowered(int a_BlockX, int a_BlockY, int a_BlockZ);
+
+
+ /** Returns if lever metadata marks it as emitting power */
+ bool IsLeverOn(NIBBLETYPE a_BlockMeta);
+ /** Returns if button metadata marks it as emitting power */
+ bool IsButtonOn(NIBBLETYPE a_BlockMeta);
+ /* ============================== */
+
+ /* ====== Misc Functions ====== */
+ /** Returns if a block is viable to be the MiddleBlock of a SetLinkedPowered operation */
+ inline static bool IsViableMiddleBlock(BLOCKTYPE Block) { return g_BlockFullyOccupiesVoxel[Block]; }
+
+ /** Returns if a block is a mechanism (something that accepts power and does something) */
+ inline static bool IsMechanism(BLOCKTYPE Block)
+ {
+ switch (Block)
+ {
+ case E_BLOCK_ACTIVATOR_RAIL:
+ case E_BLOCK_COMMAND_BLOCK:
+ case E_BLOCK_PISTON:
+ case E_BLOCK_STICKY_PISTON:
+ case E_BLOCK_DISPENSER:
+ case E_BLOCK_DROPPER:
+ case E_BLOCK_FENCE_GATE:
+ case E_BLOCK_HOPPER:
+ case E_BLOCK_NOTE_BLOCK:
+ case E_BLOCK_TNT:
+ case E_BLOCK_TRAPDOOR:
+ case E_BLOCK_REDSTONE_LAMP_OFF:
+ case E_BLOCK_REDSTONE_LAMP_ON:
+ case E_BLOCK_WOODEN_DOOR:
+ case E_BLOCK_IRON_DOOR:
+ case E_BLOCK_REDSTONE_REPEATER_OFF:
+ case E_BLOCK_REDSTONE_REPEATER_ON:
+ case E_BLOCK_POWERED_RAIL:
+ {
+ return true;
+ }
+ default: return false;
+ }
+ }
+
+ /** Returns if a block has the potential to output power */
+ inline static bool IsPotentialSource(BLOCKTYPE Block)
+ {
+ switch (Block)
+ {
+ case E_BLOCK_DETECTOR_RAIL:
+ case E_BLOCK_DAYLIGHT_SENSOR:
+ case E_BLOCK_WOODEN_BUTTON:
+ case E_BLOCK_STONE_BUTTON:
+ case E_BLOCK_REDSTONE_WIRE:
+ case E_BLOCK_REDSTONE_TORCH_ON:
+ case E_BLOCK_LEVER:
+ case E_BLOCK_REDSTONE_REPEATER_ON:
+ case E_BLOCK_BLOCK_OF_REDSTONE:
+ case E_BLOCK_ACTIVE_COMPARATOR:
+ {
+ return true;
+ }
+ default: return false;
+ }
+ }
+
+ /** Returns if a block is any sort of redstone device */
+ inline static bool IsRedstone(BLOCKTYPE Block)
+ {
+ switch (Block)
+ {
+ // All redstone devices, please alpha sort
+ case E_BLOCK_ACTIVATOR_RAIL:
+ case E_BLOCK_ACTIVE_COMPARATOR:
+ case E_BLOCK_BLOCK_OF_REDSTONE:
+ case E_BLOCK_COMMAND_BLOCK:
+ case E_BLOCK_DETECTOR_RAIL:
+ case E_BLOCK_DISPENSER:
+ case E_BLOCK_DAYLIGHT_SENSOR:
+ case E_BLOCK_DROPPER:
+ case E_BLOCK_FENCE_GATE:
+ case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE:
+ case E_BLOCK_HOPPER:
+ case E_BLOCK_INACTIVE_COMPARATOR:
+ case E_BLOCK_IRON_DOOR:
+ case E_BLOCK_LEVER:
+ case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE:
+ case E_BLOCK_NOTE_BLOCK:
+ case E_BLOCK_POWERED_RAIL:
+ case E_BLOCK_REDSTONE_LAMP_OFF:
+ case E_BLOCK_REDSTONE_LAMP_ON:
+ case E_BLOCK_REDSTONE_REPEATER_OFF:
+ case E_BLOCK_REDSTONE_REPEATER_ON:
+ case E_BLOCK_REDSTONE_TORCH_OFF:
+ case E_BLOCK_REDSTONE_TORCH_ON:
+ case E_BLOCK_REDSTONE_WIRE:
+ case E_BLOCK_STICKY_PISTON:
+ case E_BLOCK_STONE_BUTTON:
+ case E_BLOCK_STONE_PRESSURE_PLATE:
+ case E_BLOCK_TNT:
+ case E_BLOCK_TRAPDOOR:
+ case E_BLOCK_TRIPWIRE_HOOK:
+ case E_BLOCK_WOODEN_BUTTON:
+ case E_BLOCK_WOODEN_DOOR:
+ case E_BLOCK_WOODEN_PRESSURE_PLATE:
+ case E_BLOCK_PISTON:
+ {
+ return true;
+ }
+ default: return false;
+ }
+ }
+};
diff --git a/src/Simulator/NoopRedstoneSimulator.h b/src/Simulator/NoopRedstoneSimulator.h
new file mode 100644
index 000000000..fe3949198
--- /dev/null
+++ b/src/Simulator/NoopRedstoneSimulator.h
@@ -0,0 +1,40 @@
+
+#pragma once
+
+#include "RedstoneSimulator.h"
+
+
+
+
+
+class cRedstoneNoopSimulator :
+ public cRedstoneSimulator
+{
+ typedef cRedstoneSimulator super;
+public:
+
+ cRedstoneNoopSimulator(cWorld & a_World) :
+ super(a_World)
+ {
+ }
+
+ //~cRedstoneNoopSimulator();
+
+ virtual void Simulate(float a_Dt) override { UNUSED(a_Dt);} // not used
+ virtual void SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) override
+ {
+ UNUSED(a_Dt);
+ UNUSED(a_ChunkX);
+ UNUSED(a_ChunkZ);
+ UNUSED(a_Chunk);
+ }
+ virtual bool IsAllowedBlock( BLOCKTYPE a_BlockType ) override { return false; }
+ virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override
+ {
+ UNUSED(a_BlockX);
+ UNUSED(a_BlockY);
+ UNUSED(a_BlockZ);
+ UNUSED(a_Chunk);
+ }
+
+} ;
diff --git a/src/Simulator/RedstoneSimulator.cpp b/src/Simulator/RedstoneSimulator.cpp
index 6b7ae3196..a83f21106 100644
--- a/src/Simulator/RedstoneSimulator.cpp
+++ b/src/Simulator/RedstoneSimulator.cpp
@@ -1,21 +1,15 @@
-#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+#include "Globals.h"
#include "RedstoneSimulator.h"
-#include "../BlockEntities/DropSpenserEntity.h"
-#include "../BlockEntities/NoteEntity.h"
-#include "../BlockEntities/CommandBlockEntity.h"
-#include "../Entities/TNTEntity.h"
-#include "../Blocks/BlockTorch.h"
-#include "../Blocks/BlockDoor.h"
-#include "../Piston.h"
+#include "../World.h"
-cRedstoneSimulator::cRedstoneSimulator(cWorld & a_World)
- : super(a_World)
+cRedstoneSimulator::cRedstoneSimulator(cWorld & a_World) :
+ super(a_World)
{
}
@@ -23,1512 +17,3 @@ cRedstoneSimulator::cRedstoneSimulator(cWorld & a_World)
-cRedstoneSimulator::~cRedstoneSimulator()
-{
-}
-
-
-
-
-
-void cRedstoneSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk)
-{
- if ((a_Chunk == NULL) || !a_Chunk->IsValid())
- {
- return;
- }
- else if ((a_BlockY < 0) || (a_BlockY > cChunkDef::Height))
- {
- return;
- }
-
- int RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width;
- int RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width;
-
- BLOCKTYPE Block;
- NIBBLETYPE Meta;
- a_Chunk->GetBlockTypeMeta(RelX, a_BlockY, RelZ, Block, Meta);
-
- // Every time a block is changed (AddBlock called), we want to go through all lists and check to see if the coordiantes stored within are still valid
- // Checking only when a block is changed, as opposed to every tick, also improves performance
-
- for (PoweredBlocksList::iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr)
- {
- if (!itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
- {
- continue;
- }
-
- if (!IsPotentialSource(Block))
- {
- LOGD("cRedstoneSimulator: Erased block @ {%i, %i, %i} from powered blocks list as it no longer connected to a source", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
- m_PoweredBlocks.erase(itr);
- break;
- }
- else if (
- // Changeable sources
- ((Block == E_BLOCK_REDSTONE_WIRE) && (Meta == 0)) ||
- ((Block == E_BLOCK_LEVER) && !IsLeverOn(Meta)) ||
- ((Block == E_BLOCK_DETECTOR_RAIL) && (Meta & 0x08) == 0) ||
- (((Block == E_BLOCK_STONE_BUTTON) || (Block == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(Meta))) ||
- (((Block == E_BLOCK_STONE_PRESSURE_PLATE) || (Block == E_BLOCK_WOODEN_PRESSURE_PLATE)) && (Meta == 0))
- )
- {
- LOGD("cRedstoneSimulator: Erased block @ {%i, %i, %i} from powered blocks list due to present/past metadata mismatch", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
- m_PoweredBlocks.erase(itr);
- break;
- }
- else if (Block == E_BLOCK_DAYLIGHT_SENSOR)
- {
- if (!a_Chunk->IsLightValid())
- {
- m_World.QueueLightChunk(a_Chunk->GetPosX(), a_Chunk->GetPosZ());
- break;
- }
- else
- {
- NIBBLETYPE SkyLight;
- a_Chunk->UnboundedRelGetBlockSkyLight(RelX, itr->a_SourcePos.y + 1, RelZ, SkyLight);
-
- if (a_Chunk->GetTimeAlteredLight(SkyLight) <= 8) // Could use SkyLight - m_World.GetSkyDarkness();
- {
- LOGD("cRedstoneSimulator: Erased daylight sensor from powered blocks list due to insufficient light level");
- m_PoweredBlocks.erase(itr);
- break;
- }
- }
- }
- }
-
- for (LinkedBlocksList::iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr)
- {
- if (itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
- {
- if (!IsPotentialSource(Block))
- {
- LOGD("cRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list as it is no longer connected to a source", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
- m_LinkedPoweredBlocks.erase(itr);
- break;
- }
- else if (
- // Things that can send power through a block but which depends on meta
- ((Block == E_BLOCK_REDSTONE_WIRE) && (Meta == 0)) ||
- ((Block == E_BLOCK_LEVER) && !IsLeverOn(Meta)) ||
- (((Block == E_BLOCK_STONE_BUTTON) || (Block == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(Meta)))
- )
- {
- LOGD("cRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list due to present/past metadata mismatch", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
- m_LinkedPoweredBlocks.erase(itr);
- break;
- }
- }
- else if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
- {
- if (!IsViableMiddleBlock(Block))
- {
- LOGD("cRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list as it is no longer powered through a valid middle block", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
- m_LinkedPoweredBlocks.erase(itr);
- break;
- }
- }
- }
-
- for (SimulatedPlayerToggleableList::iterator itr = m_SimulatedPlayerToggleableBlocks.begin(); itr != m_SimulatedPlayerToggleableBlocks.end(); ++itr)
- {
- if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
- {
- continue;
- }
-
- if (!IsAllowedBlock(Block))
- {
- LOGD("cRedstoneSimulator: Erased block @ {%i, %i, %i} from toggleable simulated list as it is no longer redstone", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
- m_SimulatedPlayerToggleableBlocks.erase(itr);
- break;
- }
- }
-
- for (RepeatersDelayList::iterator itr = m_RepeatersDelayList.begin(); itr != m_RepeatersDelayList.end(); ++itr)
- {
- if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
- {
- continue;
- }
-
- if ((Block != E_BLOCK_REDSTONE_REPEATER_ON) && (Block != E_BLOCK_REDSTONE_REPEATER_OFF))
- {
- m_RepeatersDelayList.erase(itr);
- break;
- }
- }
-
- cRedstoneSimulatorChunkData & ChunkData = a_Chunk->GetRedstoneSimulatorData();
- for (cRedstoneSimulatorChunkData::iterator itr = ChunkData.begin(); itr != ChunkData.end(); ++itr)
- {
- if ((itr->x == RelX) && (itr->y == a_BlockY) && (itr->z == RelZ)) // We are at an entry matching the current (changed) block
- {
- if (!IsAllowedBlock(Block))
- {
- itr->DataTwo = true; // The new blocktype is not redstone; it must be queued to be removed from this list
- }
- else
- {
- itr->Data = Block; // Update block information
- }
- return;
- }
- }
-
- if (!IsAllowedBlock(Block))
- {
- return;
- }
-
- ChunkData.push_back(cCoordWithBlockAndBool(RelX, a_BlockY, RelZ, Block, false));
-}
-
-
-
-
-
-void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk)
-{
- // We still attempt to simulate all blocks in the chunk every tick, because of outside influence that needs to be taken into account
- // For example, repeaters need to be ticked, pressure plates checked for entities, daylight sensor checked for light changes, etc.
- // The easiest way to make this more efficient is probably just to reduce code within the handlers that put too much strain on server, like getting or setting blocks
- // A marking dirty system might be a TODO for later on, perhaps
-
- cRedstoneSimulatorChunkData & ChunkData = a_Chunk->GetRedstoneSimulatorData();
- if (ChunkData.empty())
- {
- return;
- }
-
- int BaseX = a_Chunk->GetPosX() * cChunkDef::Width;
- int BaseZ = a_Chunk->GetPosZ() * cChunkDef::Width;
-
- for (cRedstoneSimulatorChunkData::iterator dataitr = ChunkData.begin(); dataitr != ChunkData.end();)
- {
- if (dataitr->DataTwo)
- {
- dataitr = ChunkData.erase(dataitr);
- continue;
- }
-
- int a_X = BaseX + dataitr->x;
- int a_Z = BaseZ + dataitr->z;
- switch (dataitr->Data)
- {
- case E_BLOCK_BLOCK_OF_REDSTONE: HandleRedstoneBlock(a_X, dataitr->y, a_Z); break;
- case E_BLOCK_LEVER: HandleRedstoneLever(a_X, dataitr->y, a_Z); break;
- case E_BLOCK_TNT: HandleTNT(a_X, dataitr->y, a_Z); break;
- case E_BLOCK_TRAPDOOR: HandleTrapdoor(a_X, dataitr->y, a_Z); break;
- case E_BLOCK_REDSTONE_WIRE: HandleRedstoneWire(a_X, dataitr->y, a_Z); break;
- case E_BLOCK_NOTE_BLOCK: HandleNoteBlock(a_X, dataitr->y, a_Z); break;
- case E_BLOCK_DAYLIGHT_SENSOR: HandleDaylightSensor(a_X, dataitr->y, a_Z); break;
- case E_BLOCK_COMMAND_BLOCK: HandleCommandBlock(a_X, dataitr->y, a_Z); break;
-
- case E_BLOCK_REDSTONE_TORCH_OFF:
- case E_BLOCK_REDSTONE_TORCH_ON:
- {
- HandleRedstoneTorch(a_X, dataitr->y, a_Z, dataitr->Data);
- break;
- }
- case E_BLOCK_STONE_BUTTON:
- case E_BLOCK_WOODEN_BUTTON:
- {
- HandleRedstoneButton(a_X, dataitr->y, a_Z, dataitr->Data);
- break;
- }
- case E_BLOCK_REDSTONE_REPEATER_OFF:
- case E_BLOCK_REDSTONE_REPEATER_ON:
- {
- HandleRedstoneRepeater(a_X, dataitr->y, a_Z, dataitr->Data);
- break;
- }
- case E_BLOCK_PISTON:
- case E_BLOCK_STICKY_PISTON:
- {
- HandlePiston(a_X, dataitr->y, a_Z);
- break;
- }
- case E_BLOCK_REDSTONE_LAMP_OFF:
- case E_BLOCK_REDSTONE_LAMP_ON:
- {
- HandleRedstoneLamp(a_X, dataitr->y, a_Z, dataitr->Data);
- break;
- }
- case E_BLOCK_DISPENSER:
- case E_BLOCK_DROPPER:
- {
- HandleDropSpenser(a_X, dataitr->y, a_Z);
- break;
- }
- case E_BLOCK_WOODEN_DOOR:
- case E_BLOCK_IRON_DOOR:
- {
- HandleDoor(a_X, dataitr->y, a_Z);
- break;
- }
- case E_BLOCK_ACTIVATOR_RAIL:
- case E_BLOCK_DETECTOR_RAIL:
- case E_BLOCK_POWERED_RAIL:
- {
- HandleRail(a_X, dataitr->y, a_Z, dataitr->Data);
- break;
- }
- case E_BLOCK_WOODEN_PRESSURE_PLATE:
- case E_BLOCK_STONE_PRESSURE_PLATE:
- {
- HandlePressurePlate(a_X, dataitr->y, a_Z, dataitr->Data);
- break;
- }
- }
- ++dataitr;
- }
-}
-
-
-
-
-
-void cRedstoneSimulator::HandleRedstoneTorch(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState)
-{
- static const struct // Define which directions the torch can power
- {
- int x, y, z;
- } gCrossCoords[] =
- {
- { 1, 0, 0},
- {-1, 0, 0},
- { 0, 0, 1},
- { 0, 0, -1},
- { 0, 1, 0},
- } ;
-
- if (a_MyState == E_BLOCK_REDSTONE_TORCH_ON)
- {
- // Check if the block the torch is on is powered
- int X = a_BlockX; int Y = a_BlockY; int Z = a_BlockZ;
- AddFaceDirection(X, Y, Z, cBlockTorchHandler::MetaDataToDirection(m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)), true); // Inverse true to get the block torch is on
-
- if (AreCoordsDirectlyPowered(X, Y, Z))
- {
- // There was a match, torch goes off
- m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_OFF, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ));
- return;
- }
-
- // Torch still on, make all 4(X, Z) + 1(Y) sides powered
- for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++)
- {
- BLOCKTYPE Type = m_World.GetBlock(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z);
- if (i + 1 < ARRAYCOUNT(gCrossCoords)) // Sides of torch, not top (top is last)
- {
- if (
- ((IsMechanism(Type)) || (Type == E_BLOCK_REDSTONE_WIRE)) && // Is it a mechanism or wire? Not block/other torch etc.
- (!Vector3i(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z).Equals(Vector3i(X, Y, Z))) // CAN'T power block is that it is on
- )
- {
- SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON);
- }
- }
- else
- {
- // Top side, power whatever is there, including blocks
- SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON);
- // Power all blocks surrounding block above torch
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YP, E_BLOCK_REDSTONE_TORCH_ON);
- }
- }
-
- if (m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) != 0x5) // Is torch standing on ground? If NOT (i.e. on wall), power block beneath
- {
- BLOCKTYPE Type = m_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ);
-
- if ((IsMechanism(Type)) || (Type == E_BLOCK_REDSTONE_WIRE)) // Still can't make a normal block powered though!
- {
- SetBlockPowered(a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON);
- }
- }
- }
- else
- {
- // Check if the block the torch is on is powered
- int X = a_BlockX; int Y = a_BlockY; int Z = a_BlockZ;
- AddFaceDirection(X, Y, Z, cBlockTorchHandler::MetaDataToDirection(m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)), true); // Inverse true to get the block torch is on
-
- // See if off state torch can be turned on again
- if (AreCoordsDirectlyPowered(X, Y, Z))
- {
- return; // Something matches, torch still powered
- }
-
- // Block torch on not powered, can be turned on again!
- m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ));
- }
-}
-
-
-
-
-
-void cRedstoneSimulator::HandleRedstoneBlock(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_BLOCK_OF_REDSTONE);
- SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_BLOCK_OF_REDSTONE); // Set self as powered
-}
-
-
-
-
-
-void cRedstoneSimulator::HandleRedstoneLever(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- if (IsLeverOn(m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)))
- {
- SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_LEVER);
-
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_LEVER);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_LEVER);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, E_BLOCK_LEVER);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YP, E_BLOCK_LEVER);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_LEVER);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_LEVER);
- }
-}
-
-
-
-
-
-void cRedstoneSimulator::HandleRedstoneButton(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType)
-{
- if (IsButtonOn(m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)))
- {
- SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, a_BlockType);
-
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, a_BlockType);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, a_BlockType);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, a_BlockType);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YP, a_BlockType);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, a_BlockType);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, a_BlockType);
- }
-}
-
-
-
-
-
-void cRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- static const struct // Define which directions the wire can receive power from
- {
- int x, y, z;
- } gCrossCoords[] =
- {
- { 1, 0, 0}, /* Wires on same level start */
- {-1, 0, 0},
- { 0, 0, 1},
- { 0, 0, -1}, /* Wires on same level stop */
- { 1, 1, 0}, /* Wires one higher, surrounding self start */
- {-1, 1, 0},
- { 0, 1, 1},
- { 0, 1, -1}, /* Wires one higher, surrounding self stop */
- { 1,-1, 0}, /* Wires one lower, surrounding self start */
- {-1,-1, 0},
- { 0,-1, 1},
- { 0,-1, -1}, /* Wires one lower, surrounding self stop */
- } ;
-
- static const struct // Define which directions the wire will check for repeater prescence
- {
- int x, y, z;
- } gSideCoords[] =
- {
- { 1, 0, 0 },
- {-1, 0, 0 },
- { 0, 0, 1 },
- { 0, 0,-1 },
- { 0, 1, 0 },
- };
-
- // Check to see if directly beside a power source
- if (IsWirePowered(a_BlockX, a_BlockY, a_BlockZ))
- {
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 15); // Maximum power
- }
- else
- {
- NIBBLETYPE MetaToSet = 0;
- NIBBLETYPE MyMeta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
- int TimesMetaSmaller = 0, TimesFoundAWire = 0;
-
- for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through all directions to transfer or receive power
- {
- if ((i >= 4) && (i <= 7)) // If we are currently checking for wire surrounding ourself one block above...
- {
- if (g_BlockIsSolid[m_World.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ)]) // If there is something solid above us (wire cut off)...
- {
- continue; // We don't receive power from that wire
- }
- }
- else if ((i >= 8) && (i <= 11)) // See above, but this is for wire below us
- {
- if (g_BlockIsSolid[m_World.GetBlock(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y + 1, a_BlockZ + gCrossCoords[i].z)])
- {
- continue;
- }
- }
-
- BLOCKTYPE SurroundType;
- NIBBLETYPE SurroundMeta;
- m_World.GetBlockTypeMeta(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, SurroundType, SurroundMeta);
-
- if (SurroundType == E_BLOCK_REDSTONE_WIRE)
- {
- TimesFoundAWire++;
-
- if (SurroundMeta > 1) // Wires of power 1 or 0 cannot transfer power TO ME, don't bother checking
- {
- // Does surrounding wire have a higher power level than self?
- // >= to fix a bug where wires bordering each other with the same power level will appear (in terms of meta) to power each other, when they aren't actually in the powered list
- if (SurroundMeta >= MyMeta)
- {
- MetaToSet = SurroundMeta - 1; // To improve performance
- }
- }
-
- if (SurroundMeta < MyMeta) // Go through all surroundings to see if self power is larger than everyone else's
- {
- TimesMetaSmaller++;
- }
- }
- }
-
- if (TimesMetaSmaller == TimesFoundAWire)
- {
- // All surrounding metas were smaller - self must have been a wire that was
- // transferring power to other wires around.
- // However, self not directly powered anymore, so source must have been removed,
- // therefore, self must be set to meta zero
- m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, 0); // SetMeta & WakeUpSims doesn't seem to work here, so SetBlock
- return; // No need to process block power sets because self not powered
- }
- else
- {
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, MetaToSet);
- }
- }
-
- if (m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) != 0) // A powered wire
- {
- for (size_t i = 0; i < ARRAYCOUNT(gSideCoords); i++) // Look for repeaters immediately surrounding self and try to power them
- {
- if (m_World.GetBlock(a_BlockX + gSideCoords[i].x, a_BlockY + gSideCoords[i].y, a_BlockZ + gSideCoords[i].z) == E_BLOCK_REDSTONE_REPEATER_OFF)
- {
- SetBlockPowered(a_BlockX + gSideCoords[i].x, a_BlockY + gSideCoords[i].y, a_BlockZ + gSideCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
- }
- }
-
- // Wire still powered, power blocks beneath
- SetBlockPowered(a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, E_BLOCK_REDSTONE_WIRE);
-
- switch (GetWireDirection(a_BlockX, a_BlockY, a_BlockZ))
- {
- case REDSTONE_NONE:
- {
- SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
-
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_REDSTONE_WIRE);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_REDSTONE_WIRE);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, E_BLOCK_REDSTONE_WIRE);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YP, E_BLOCK_REDSTONE_WIRE);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_REDSTONE_WIRE);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_REDSTONE_WIRE);
- break;
- }
- case REDSTONE_X_POS:
- {
- SetBlockPowered(a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_REDSTONE_WIRE);
- break;
- }
- case REDSTONE_X_NEG:
- {
- SetBlockPowered(a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_REDSTONE_WIRE);
- break;
- }
- case REDSTONE_Z_POS:
- {
- SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_REDSTONE_WIRE);
- break;
- }
- case REDSTONE_Z_NEG:
- {
- SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_REDSTONE_WIRE);
- break;
- }
- }
- }
-}
-
-
-
-
-
-void cRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState)
-{
- NIBBLETYPE a_Meta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
-
- bool IsOn = ((a_MyState == E_BLOCK_REDSTONE_REPEATER_ON) ? true : false); // Cache if repeater is on
- bool IsSelfPowered = IsRepeaterPowered(a_BlockX, a_BlockY, a_BlockZ, a_Meta & 0x3); // Cache if repeater is pwoered
-
- if (IsSelfPowered && !IsOn) // Queue a power change if I am receiving power but not on
- {
- QueueRepeaterPowerChange(a_BlockX, a_BlockY, a_BlockZ, a_Meta, 0, true);
- }
- else if (!IsSelfPowered && IsOn) // Queue a power change if I am not receiving power but on
- {
- QueueRepeaterPowerChange(a_BlockX, a_BlockY, a_BlockZ, a_Meta, 0, false);
- }
-
- for (RepeatersDelayList::iterator itr = m_RepeatersDelayList.begin(); itr != m_RepeatersDelayList.end(); ++itr)
- {
- if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
- {
- continue;
- }
-
- if (itr->a_ElapsedTicks >= itr->a_DelayTicks) // Has the elapsed ticks reached the target ticks?
- {
- if (itr->ShouldPowerOn)
- {
- if (!IsOn)
- {
- m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON, a_Meta); // For performance
- }
-
- switch (a_Meta & 0x3) // We only want the direction (bottom) bits
- {
- case 0x0:
- {
- SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_REDSTONE_REPEATER_ON);
- break;
- }
- case 0x1:
- {
- SetBlockPowered(a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_REDSTONE_REPEATER_ON);
- break;
- }
- case 0x2:
- {
- SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_REDSTONE_REPEATER_ON);
- break;
- }
- case 0x3:
- {
- SetBlockPowered(a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON);
- SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_REDSTONE_REPEATER_ON);
- break;
- }
- }
-
- // Removal of the data entry will be handled in SimChunk - we still want to continue trying to power blocks, even if our delay time has reached
- // Otherwise, the power state of blocks in front won't update after we have powered on
- return;
- }
- else
- {
- if (IsOn)
- {
- m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_OFF, a_Meta);
- }
- m_RepeatersDelayList.erase(itr); // We can remove off repeaters which don't need further updating
- return;
- }
- }
- else
- {
- // Apparently, incrementing ticks only works reliably here, and not in SimChunk;
- // With a world with lots of redstone, the repeaters simply do not delay
- // I am confounded to say why. Perhaps optimisation failure.
- LOGD("Incremented a repeater @ {%i %i %i} | Elapsed ticks: %i | Target delay: %i", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z, itr->a_ElapsedTicks, itr->a_DelayTicks);
- itr->a_ElapsedTicks++;
- }
- }
-}
-
-
-
-
-
-void cRedstoneSimulator::HandlePiston(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- cPiston Piston(&m_World);
- if (IsPistonPowered(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x7)) // We only want the bottom three bits (4th controls extended-ness)
- {
- Piston.ExtendPiston(a_BlockX, a_BlockY, a_BlockZ);
- }
- else
- {
- Piston.RetractPiston(a_BlockX, a_BlockY, a_BlockZ);
- }
-}
-
-
-
-
-
-void cRedstoneSimulator::HandleDropSpenser(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- class cSetPowerToDropSpenser :
- public cDropSpenserCallback
- {
- bool m_IsPowered;
- public:
- cSetPowerToDropSpenser(bool a_IsPowered) : m_IsPowered(a_IsPowered) {}
-
- virtual bool Item(cDropSpenserEntity * a_DropSpenser) override
- {
- a_DropSpenser->SetRedstonePower(m_IsPowered);
- return false;
- }
- } DrSpSP (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ));
-
- m_World.DoWithDropSpenserAt(a_BlockX, a_BlockY, a_BlockZ, DrSpSP);
-}
-
-
-
-
-
-void cRedstoneSimulator::HandleRedstoneLamp(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState)
-{
- if (a_MyState == E_BLOCK_REDSTONE_LAMP_OFF)
- {
- if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ))
- {
- m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_LAMP_ON, 0);
- }
- }
- else
- {
- if (!AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ))
- {
- m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_LAMP_OFF, 0);
- }
- }
-}
-
-
-
-
-
-void cRedstoneSimulator::HandleTNT(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ))
- {
- m_World.BroadcastSoundEffect("random.fuse", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.6f);
- m_World.SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, 4); // 4 seconds to boom
- m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
- }
-}
-
-
-
-
-
-void cRedstoneSimulator::HandleDoor(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ))
- {
- if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, true))
- {
- cChunkInterface ChunkInterface(m_World.GetChunkMap());
- cBlockDoorHandler::ChangeDoor(ChunkInterface, a_BlockX, a_BlockY, a_BlockZ);
- SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, true);
- }
- }
- else
- {
- if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, false))
- {
- cChunkInterface ChunkInterface(m_World.GetChunkMap());
- cBlockDoorHandler::ChangeDoor(ChunkInterface, a_BlockX, a_BlockY, a_BlockZ);
- SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, false);
- }
- }
-}
-
-
-
-
-
-void cRedstoneSimulator::HandleCommandBlock(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- class cSetPowerToCommandBlock :
- public cCommandBlockCallback
- {
- bool m_IsPowered;
- public:
- cSetPowerToCommandBlock(bool a_IsPowered) : m_IsPowered(a_IsPowered) {}
-
- virtual bool Item(cCommandBlockEntity * a_CommandBlock) override
- {
- a_CommandBlock->SetRedstonePower(m_IsPowered);
- return false;
- }
- } CmdBlockSP (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ));
-
- m_World.DoWithCommandBlockAt(a_BlockX, a_BlockY, a_BlockZ, CmdBlockSP);
-}
-
-
-
-
-
-void cRedstoneSimulator::HandleRail(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType)
-{
- switch (a_MyType)
- {
- case E_BLOCK_DETECTOR_RAIL:
- {
- if ((m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x08) == 0x08)
- {
- SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, a_MyType);
- }
- break;
- }
- case E_BLOCK_ACTIVATOR_RAIL:
- case E_BLOCK_POWERED_RAIL:
- {
- if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ))
- {
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) | 0x08);
- }
- else
- {
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x07);
- }
- break;
- }
- default: LOGD("Unhandled type of rail in %s", __FUNCTION__);
- }
-}
-
-
-
-
-
-void cRedstoneSimulator::HandleTrapdoor(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ))
- {
- if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, true))
- {
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) | 0x4);
- SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, true);
- }
- }
- else
- {
- if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, false))
- {
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0xB); // Take into account that the fourth bit is needed for trapdoors too
- SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, false);
- }
- }
-}
-
-
-
-
-
-void cRedstoneSimulator::HandleNoteBlock(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- bool m_bAreCoordsPowered = AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ);
-
- if (m_bAreCoordsPowered)
- {
- if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, true))
- {
- class cSetPowerToNoteBlock :
- public cNoteBlockCallback
- {
- bool m_IsPowered;
- public:
- cSetPowerToNoteBlock(bool a_IsPowered) : m_IsPowered(a_IsPowered) {}
-
- virtual bool Item(cNoteEntity * a_NoteBlock) override
- {
- if (m_IsPowered)
- {
- a_NoteBlock->MakeSound();
- }
- return false;
- }
- } NoteBlockSP(m_bAreCoordsPowered);
-
- m_World.DoWithNoteBlockAt(a_BlockX, a_BlockY, a_BlockZ, NoteBlockSP);
- SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, true);
- }
- }
- else
- {
- if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, false))
- {
- SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, false);
- }
- }
-}
-
-
-
-
-
-void cRedstoneSimulator::HandleDaylightSensor(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- int a_ChunkX, a_ChunkZ;
- cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, a_ChunkX, a_ChunkZ);
-
- if (!m_World.IsChunkLighted(a_ChunkX, a_ChunkZ))
- {
- m_World.QueueLightChunk(a_ChunkX, a_ChunkZ);
- }
- else
- {
- NIBBLETYPE SkyLight = m_World.GetBlockSkyLight(a_BlockX, a_BlockY + 1, a_BlockZ) - m_World.GetSkyDarkness();
- if (SkyLight > 8)
- {
- SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_DAYLIGHT_SENSOR);
- }
- }
-}
-
-
-
-
-
-void cRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType)
-{
- switch (a_MyType)
- {
- case E_BLOCK_STONE_PRESSURE_PLATE:
- {
- // MCS feature - stone pressure plates can only be triggered by players :D
- cPlayer * a_Player = m_World.FindClosestPlayer(Vector3f(a_BlockX + 0.5f, (float)a_BlockY, a_BlockZ + 0.5f), 0.5f, false);
-
- if (a_Player != NULL)
- {
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x1);
- SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_STONE_PRESSURE_PLATE);
- }
- else
- {
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x0);
- m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ);
- }
- break;
- }
- case E_BLOCK_WOODEN_PRESSURE_PLATE:
- {
- class cWoodenPressurePlateCallback :
- public cEntityCallback
- {
- public:
- cWoodenPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
- m_X(a_BlockX),
- m_Y(a_BlockY),
- m_Z(a_BlockZ),
- m_World(a_World),
- m_Entity(NULL)
- {
- }
-
- virtual bool Item(cEntity * a_Entity) override
- {
- Vector3f EntityPos = a_Entity->GetPosition();
- Vector3f BlockPos(m_X + 0.5f, (float)m_Y, m_Z + 0.5f);
- float Distance = (EntityPos - BlockPos).Length();
-
- if (Distance < 0.5)
- {
- m_Entity = a_Entity;
- return true; // Break out, we only need to know for wooden plates that at least one entity is on top
- }
- return false;
- }
-
- bool FoundEntity(void) const
- {
- return m_Entity != NULL;
- }
-
- protected:
- cEntity * m_Entity;
- cWorld * m_World;
-
- int m_X;
- int m_Y;
- int m_Z;
- } ;
-
- cWoodenPressurePlateCallback WoodenPressurePlateCallback(a_BlockX, a_BlockY, a_BlockZ, &m_World);
- m_World.ForEachEntity(WoodenPressurePlateCallback);
-
- if (WoodenPressurePlateCallback.FoundEntity())
- {
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x1);
- SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_WOODEN_PRESSURE_PLATE);
- }
- else
- {
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x0);
- m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ);
- }
- break;
- }
- default:
- LOGD("Unimplemented pressure plate type %s in cRedstoneSimulator", ItemToFullString(a_MyType).c_str());
- break;
- }
-}
-
-
-
-
-
-bool cRedstoneSimulator::AreCoordsDirectlyPowered(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr) // Check powered list
- {
- if (itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
- {
- return true;
- }
- }
- return false;
-}
-
-
-
-
-
-bool cRedstoneSimulator::AreCoordsLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr) // Check linked powered list
- {
- if (itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
- {
- return true;
- }
- }
- return false;
-}
-
-
-
-
-
-bool cRedstoneSimulator::IsRepeaterPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta)
-{
- // Repeaters cannot be powered by any face except their back; verify that this is true for a source
-
- for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr)
- {
- if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; }
-
- switch (a_Meta)
- {
- case 0x0:
- {
- // Flip the coords to check the back of the repeater
- if (itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ + 1))) { return true; }
- break;
- }
- case 0x1:
- {
- if (itr->a_SourcePos.Equals(Vector3i(a_BlockX - 1, a_BlockY, a_BlockZ))) { return true; }
- break;
- }
- case 0x2:
- {
- if (itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ - 1))) { return true; }
- break;
- }
- case 0x3:
- {
- if (itr->a_SourcePos.Equals(Vector3i(a_BlockX + 1, a_BlockY, a_BlockZ))) { return true; }
- break;
- }
- }
- }
-
- for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr)
- {
- if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; }
-
- switch (a_Meta)
- {
- case 0x0:
- {
- if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ + 1))) { return true; }
- break;
- }
- case 0x1:
- {
- if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX - 1, a_BlockY, a_BlockZ))) { return true; }
- break;
- }
- case 0x2:
- {
- if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ - 1))) { return true; }
- break;
- }
- case 0x3:
- {
- if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX + 1, a_BlockY, a_BlockZ))) { return true; }
- break;
- }
- }
- }
- return false; // Couldn't find power source behind repeater
-}
-
-
-
-
-bool cRedstoneSimulator::IsPistonPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta)
-{
- // Pistons cannot be powered through their front face; this function verifies that a source meets this requirement
-
- int OldX = a_BlockX, OldY = a_BlockY, OldZ = a_BlockZ;
- eBlockFace Face = cPiston::MetaDataToDirection(a_Meta);
-
- for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr)
- {
- if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; }
-
- AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, Face);
-
- if (!itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
- {
- return true;
- }
-
- a_BlockX = OldX;
- a_BlockY = OldY;
- a_BlockZ = OldZ;
- }
-
- for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr)
- {
- if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; }
-
- AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, Face);
-
- if (!itr->a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
- {
- return true;
- }
-
- a_BlockX = OldX;
- a_BlockY = OldY;
- a_BlockZ = OldZ;
- }
- return false; // Source was in front of the piston's front face
-}
-
-
-
-
-bool cRedstoneSimulator::IsWirePowered(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr)
- {
- if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; }
-
- if (m_World.GetBlock(itr->a_SourcePos) != E_BLOCK_REDSTONE_WIRE)
- {
- return true;
- }
- }
-
- for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr)
- {
- if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; }
-
- if (m_World.GetBlock(itr->a_SourcePos) != E_BLOCK_REDSTONE_WIRE)
- {
- return true;
- }
- }
- return false; // Source was in front of the piston's front face
-}
-
-
-
-
-
-bool cRedstoneSimulator::AreCoordsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool IsCurrentStatePowered)
-{
- for (SimulatedPlayerToggleableList::const_iterator itr = m_SimulatedPlayerToggleableBlocks.begin(); itr != m_SimulatedPlayerToggleableBlocks.end(); ++itr)
- {
- if (itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
- {
- if (itr->WasLastStatePowered != IsCurrentStatePowered) // Was the last power state different to the current?
- {
- return false; // It was, coordinates are no longer simulated
- }
- else
- {
- return true; // It wasn't, don't resimulate block, and allow players to toggle
- }
- }
- }
- return false; // Block wasn't even in the list, not simulated
-}
-
-
-
-
-
-void cRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Direction, BLOCKTYPE a_SourceType)
-{
- switch (a_Direction)
- {
- case BLOCK_FACE_XM:
- {
- BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ);
-
- SetBlockLinkedPowered(a_BlockX - 2, a_BlockY, a_BlockZ, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX - 1, a_BlockY + 1, a_BlockZ, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX - 1, a_BlockY - 1, a_BlockZ, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ + 1, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ - 1, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
-
- break;
- }
- case BLOCK_FACE_XP:
- {
- BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ);
-
- SetBlockLinkedPowered(a_BlockX + 2, a_BlockY, a_BlockZ, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX + 1, a_BlockY + 1, a_BlockZ, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX + 1, a_BlockY - 1, a_BlockZ, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ + 1, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ - 1, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
-
- break;
- }
- case BLOCK_FACE_YM:
- {
- BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ);
-
- SetBlockLinkedPowered(a_BlockX, a_BlockY - 2, a_BlockZ, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX + 1, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX - 1, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ + 1, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ - 1, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
-
- break;
- }
- case BLOCK_FACE_YP:
- {
- BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ);
-
- SetBlockLinkedPowered(a_BlockX, a_BlockY + 2, a_BlockZ, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX + 1, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX - 1, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ + 1, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ - 1, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
-
- break;
- }
- case BLOCK_FACE_ZM:
- {
- BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ - 1);
-
- SetBlockLinkedPowered(a_BlockX, a_BlockY, a_BlockZ - 2, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
-
- break;
- }
- case BLOCK_FACE_ZP:
- {
- BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1);
-
- SetBlockLinkedPowered(a_BlockX, a_BlockY, a_BlockZ + 2, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
- SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
-
- break;
- }
- default:
- {
- ASSERT(!"Unhandled face direction when attempting to set blocks as linked powered!"); // Zombies, that wasn't supposed to happen...
- break;
- }
- }
-}
-
-
-
-
-
-void cRedstoneSimulator::SetAllDirsAsPowered(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_SourceBlock)
-{
- static const struct
- {
- int x, y, z;
- } gCrossCoords[] =
- {
- { 1, 0, 0 },
- {-1, 0, 0 },
- { 0, 0, 1 },
- { 0, 0,-1 },
- { 0, 1, 0 },
- { 0,-1, 0 }
- };
-
- for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through struct to power all directions
- {
- SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, a_SourceBlock);
- }
-}
-
-
-
-
-
-void cRedstoneSimulator::SetBlockPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock)
-{
- BLOCKTYPE Block = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ);
- if (Block == E_BLOCK_AIR)
- {
- // Don't set air, fixes some bugs (wires powering themselves)
- return;
- }
-
- for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr) // Check powered list
- {
- if (
- itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)) &&
- itr->a_SourcePos.Equals(Vector3i(a_SourceX, a_SourceY, a_SourceZ))
- )
- {
- // Check for duplicates
- return;
- }
- }
-
- sPoweredBlocks RC;
- RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ);
- RC.a_SourcePos = Vector3i(a_SourceX, a_SourceY, a_SourceZ);
- m_PoweredBlocks.push_back(RC);
-}
-
-
-
-
-
-void cRedstoneSimulator::SetBlockLinkedPowered(
- int a_BlockX, int a_BlockY, int a_BlockZ,
- int a_MiddleX, int a_MiddleY, int a_MiddleZ,
- int a_SourceX, int a_SourceY, int a_SourceZ,
- BLOCKTYPE a_SourceBlock, BLOCKTYPE a_MiddleBlock
-)
-{
- BLOCKTYPE DestBlock = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ);
- if (DestBlock == E_BLOCK_AIR)
- {
- // Don't set air, fixes some bugs (wires powering themselves)
- return;
- }
- if (!IsViableMiddleBlock(a_MiddleBlock))
- {
- return;
- }
-
- for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr) // Check linked powered list
- {
- if (
- itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)) &&
- itr->a_MiddlePos.Equals(Vector3i(a_MiddleX, a_MiddleY, a_MiddleZ)) &&
- itr->a_SourcePos.Equals(Vector3i(a_SourceX, a_SourceY, a_SourceZ))
- )
- {
- // Check for duplicates
- return;
- }
- }
-
- sLinkedPoweredBlocks RC;
- RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ);
- RC.a_MiddlePos = Vector3i(a_MiddleX, a_MiddleY, a_MiddleZ);
- RC.a_SourcePos = Vector3i(a_SourceX, a_SourceY, a_SourceZ);
- m_LinkedPoweredBlocks.push_back(RC);
-}
-
-
-
-
-
-void cRedstoneSimulator::SetPlayerToggleableBlockAsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool WasLastStatePowered)
-{
- for (SimulatedPlayerToggleableList::iterator itr = m_SimulatedPlayerToggleableBlocks.begin(); itr != m_SimulatedPlayerToggleableBlocks.end(); ++itr)
- {
- if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
- {
- continue;
- }
-
- if (itr->WasLastStatePowered != WasLastStatePowered)
- {
- // If power states different, update listing
- itr->WasLastStatePowered = WasLastStatePowered;
- return;
- }
- else
- {
- // If states the same, just ignore
- return;
- }
- }
-
- // We have arrive here; no block must be in list - add one
- sSimulatedPlayerToggleableList RC;
- RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ);
- RC.WasLastStatePowered = WasLastStatePowered;
- m_SimulatedPlayerToggleableBlocks.push_back(RC);
-}
-
-
-
-
-
-void cRedstoneSimulator::QueueRepeaterPowerChange(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta, short a_ElapsedTicks, bool ShouldPowerOn)
-{
- for (RepeatersDelayList::iterator itr = m_RepeatersDelayList.begin(); itr != m_RepeatersDelayList.end(); ++itr)
- {
- if (itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
- {
- if (ShouldPowerOn == itr->ShouldPowerOn) // We are queued already for the same thing, don't replace entry
- {
- return;
- }
-
- // Already in here (normal to allow repeater to continue on powering and updating blocks in front) - just update info and quit
- itr->a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + (ShouldPowerOn ? 1 : 0)) * 2; // See below for description
- itr->a_ElapsedTicks = 0;
- itr->ShouldPowerOn = ShouldPowerOn;
- return;
- }
- }
-
- // Self not in list, add self to list
- sRepeatersDelayList RC;
- RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ);
-
- // Gets the top two bits (delay time), shifts them into the lower two bits, and adds one (meta 0 = 1 tick; 1 = 2 etc.)
- // * 2 because apparently, MCS ticks are way faster than vanilla ticks, so repeater aren't noticeably delayed
- // We don't +1 when powering off because everything seems to already delay a tick when powering off, why? No idea :P
- RC.a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + (ShouldPowerOn ? 1 : 0)) * 2;
-
-
- RC.a_ElapsedTicks = 0;
- RC.ShouldPowerOn = ShouldPowerOn;
- m_RepeatersDelayList.push_back(RC);
- return;
-}
-
-
-
-
-
-cRedstoneSimulator::eRedstoneDirection cRedstoneSimulator::GetWireDirection(int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- int Dir = REDSTONE_NONE;
-
- BLOCKTYPE NegX = m_World.GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ);
- if (IsPotentialSource(NegX))
- {
- Dir |= (REDSTONE_X_POS);
- }
-
- BLOCKTYPE PosX = m_World.GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ);
- if (IsPotentialSource(PosX))
- {
- Dir |= (REDSTONE_X_NEG);
- }
-
- BLOCKTYPE NegZ = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ - 1);
- if (IsPotentialSource(NegZ))
- {
- if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner
- {
- Dir ^= REDSTONE_X_POS;
- Dir |= REDSTONE_X_NEG;
- }
- if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner
- {
- Dir ^= REDSTONE_X_NEG;
- Dir |= REDSTONE_X_POS;
- }
- Dir |= REDSTONE_Z_POS;
- }
-
- BLOCKTYPE PosZ = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1);
- if (IsPotentialSource(PosZ))
- {
- if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner
- {
- Dir ^= REDSTONE_X_POS;
- Dir |= REDSTONE_X_NEG;
- }
- if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner
- {
- Dir ^= REDSTONE_X_NEG;
- Dir |= REDSTONE_X_POS;
- }
- Dir |= REDSTONE_Z_NEG;
- }
- return (eRedstoneDirection)Dir;
-}
-
-
-
-
-
-bool cRedstoneSimulator::IsLeverOn(NIBBLETYPE a_BlockMeta)
-{
- // Extract the ON bit from metadata and return if true if it is set:
- return ((a_BlockMeta & 0x8) == 0x8);
-}
-
-
-
-
-
-bool cRedstoneSimulator::IsButtonOn(NIBBLETYPE a_BlockMeta)
-{
- return IsLeverOn(a_BlockMeta);
-}
-
-
-
-
diff --git a/src/Simulator/RedstoneSimulator.h b/src/Simulator/RedstoneSimulator.h
index c505b2a0f..b3e20c9a5 100644
--- a/src/Simulator/RedstoneSimulator.h
+++ b/src/Simulator/RedstoneSimulator.h
@@ -3,10 +3,6 @@
#include "Simulator.h"
-/// Per-chunk data for the simulator, specified individual chunks to simulate; 'Data' is not used
-typedef cCoordWithBlockAndBoolVector cRedstoneSimulatorChunkData;
-
-
@@ -14,250 +10,8 @@ class cRedstoneSimulator :
public cSimulator
{
typedef cSimulator super;
+
public:
-
cRedstoneSimulator(cWorld & a_World);
- ~cRedstoneSimulator();
-
- virtual void Simulate(float a_Dt) override { UNUSED(a_Dt);} // not used
- virtual void SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) override;
- virtual bool IsAllowedBlock( BLOCKTYPE a_BlockType ) override { return IsRedstone(a_BlockType); }
-
- enum eRedstoneDirection
- {
- REDSTONE_NONE = 0,
- REDSTONE_X_POS = 0x1,
- REDSTONE_X_NEG = 0x2,
- REDSTONE_Z_POS = 0x4,
- REDSTONE_Z_NEG = 0x8,
- };
- eRedstoneDirection GetWireDirection(int a_BlockX, int a_BlockY, int a_BlockZ);
-
-private:
-
- struct sPoweredBlocks // Define structure of the directly powered blocks list
- {
- Vector3i a_BlockPos; // Position of powered block
- Vector3i a_SourcePos; // Position of source powering the block at a_BlockPos
- };
-
- struct sLinkedPoweredBlocks // Define structure of the indirectly powered blocks list (i.e. repeaters powering through a block to the block at the other side)
- {
- Vector3i a_BlockPos;
- Vector3i a_MiddlePos;
- Vector3i a_SourcePos;
- };
-
- struct sSimulatedPlayerToggleableList
- {
- Vector3i a_BlockPos;
- bool WasLastStatePowered;
- };
-
- struct sRepeatersDelayList
- {
- Vector3i a_BlockPos;
- short a_DelayTicks;
- short a_ElapsedTicks;
- bool ShouldPowerOn;
- };
-
- typedef std::vector <sPoweredBlocks> PoweredBlocksList;
- typedef std::vector <sLinkedPoweredBlocks> LinkedBlocksList;
- typedef std::vector <sSimulatedPlayerToggleableList> SimulatedPlayerToggleableList;
- typedef std::vector <sRepeatersDelayList> RepeatersDelayList;
-
- PoweredBlocksList m_PoweredBlocks;
- LinkedBlocksList m_LinkedPoweredBlocks;
- SimulatedPlayerToggleableList m_SimulatedPlayerToggleableBlocks;
- RepeatersDelayList m_RepeatersDelayList;
-
- virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override;
-
- // We want a_MyState for devices needing a full FastSetBlock (as opposed to meta) because with our simulation model, we cannot keep setting the block if it is already set correctly
- // In addition to being non-performant, it would stop the player from actually breaking said device
-
- /* ====== SOURCES ====== */
- /** Handles the redstone torch */
- void HandleRedstoneTorch(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState);
- /** Handles the redstone block */
- void HandleRedstoneBlock(int a_BlockX, int a_BlockY, int a_BlockZ);
- /** Handles levers */
- void HandleRedstoneLever(int a_BlockX, int a_BlockY, int a_BlockZ);
- /** Handles buttons */
- void HandleRedstoneButton(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType);
- /** Handles daylight sensors */
- void HandleDaylightSensor(int a_BlockX, int a_BlockY, int a_BlockZ);
- /** Handles pressure plates */
- void HandlePressurePlate(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType);
- /* ==================== */
-
- /* ====== CARRIERS ====== */
- /** Handles redstone wire */
- void HandleRedstoneWire(int a_BlockX, int a_BlockY, int a_BlockZ);
- /** Handles repeaters */
- void HandleRedstoneRepeater(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState);
- /* ====================== */
-
- /* ====== DEVICES ====== */
- /** Handles pistons */
- void HandlePiston(int a_BlockX, int a_BlockY, int a_BlockZ);
- /** Handles dispensers and droppers */
- void HandleDropSpenser(int a_BlockX, int a_BlockY, int a_BlockZ);
- /** Handles TNT (exploding) */
- void HandleTNT(int a_BlockX, int a_BlockY, int a_BlockZ);
- /** Handles redstone lamps */
- void HandleRedstoneLamp(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState);
- /** Handles doords */
- void HandleDoor(int a_BlockX, int a_BlockY, int a_BlockZ);
- /** Handles command blocks */
- void HandleCommandBlock(int a_BlockX, int a_BlockY, int a_BlockZ);
- /** Handles activator, detector, and powered rails */
- void HandleRail(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType);
- /** Handles trapdoors */
- void HandleTrapdoor(int a_BlockX, int a_BlockY, int a_BlockZ);
- /** Handles noteblocks */
- void HandleNoteBlock(int a_BlockX, int a_BlockY, int a_BlockZ);
- /* ===================== */
-
- /* ====== Helper functions ====== */
- /** Marks a block as powered */
- void SetBlockPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock);
- /** Marks a block as being powered through another block */
- void SetBlockLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_MiddleX, int a_MiddleY, int a_MiddleZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock, BLOCKTYPE a_MiddeBlock);
- /** Marks a block as simulated, who should not be simulated further unless their power state changes, to accomodate a player manually toggling the block without triggering the simulator toggling it back */
- void SetPlayerToggleableBlockAsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool WasLastStatePowered);
- /** Marks the second block in a direction as linked powered */
- void SetDirectionLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Direction, BLOCKTYPE a_SourceBlock);
- /** Marks all blocks immediately surrounding a coordinate as powered */
- void SetAllDirsAsPowered(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_SourceBlock);
- /** Queues a repeater to be powered or unpowered */
- void QueueRepeaterPowerChange(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta, short a_ElapsedTicks, bool ShouldPowerOn);
-
- /** Returns if a coordinate is powered or linked powered */
- bool AreCoordsPowered(int a_BlockX, int a_BlockY, int a_BlockZ) { return AreCoordsDirectlyPowered(a_BlockX, a_BlockY, a_BlockZ) || AreCoordsLinkedPowered(a_BlockX, a_BlockY, a_BlockZ); }
- /** Returns if a coordinate is in the directly powered blocks list */
- bool AreCoordsDirectlyPowered(int a_BlockX, int a_BlockY, int a_BlockZ);
- /** Returns if a coordinate is in the indirectly powered blocks list */
- bool AreCoordsLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ);
- /** Returns if a coordinate was marked as simulated (for blocks toggleable by players) */
- bool AreCoordsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool IsCurrentStatePowered);
- /** Returns if a repeater is powered */
- bool IsRepeaterPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta);
- /** Returns if a piston is powered */
- bool IsPistonPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta);
- /** Returns if a wire is powered
- The only diffence between this and a normal AreCoordsPowered is that this function checks for a wire powering another wire
- */
- bool IsWirePowered(int a_BlockX, int a_BlockY, int a_BlockZ);
-
-
- /** Returns if lever metadata marks it as emitting power */
- bool IsLeverOn(NIBBLETYPE a_BlockMeta);
- /** Returns if button metadata marks it as emitting power */
- bool IsButtonOn(NIBBLETYPE a_BlockMeta);
- /* ============================== */
-
- /* ====== Misc Functions ====== */
- /** Returns if a block is viable to be the MiddleBlock of a SetLinkedPowered operation */
- inline static bool IsViableMiddleBlock(BLOCKTYPE Block) { return g_BlockFullyOccupiesVoxel[Block]; }
-
- /** Returns if a block is a mechanism (something that accepts power and does something) */
- inline static bool IsMechanism(BLOCKTYPE Block)
- {
- switch (Block)
- {
- case E_BLOCK_ACTIVATOR_RAIL:
- case E_BLOCK_COMMAND_BLOCK:
- case E_BLOCK_PISTON:
- case E_BLOCK_STICKY_PISTON:
- case E_BLOCK_DISPENSER:
- case E_BLOCK_DROPPER:
- case E_BLOCK_FENCE_GATE:
- case E_BLOCK_HOPPER:
- case E_BLOCK_NOTE_BLOCK:
- case E_BLOCK_TNT:
- case E_BLOCK_TRAPDOOR:
- case E_BLOCK_REDSTONE_LAMP_OFF:
- case E_BLOCK_REDSTONE_LAMP_ON:
- case E_BLOCK_WOODEN_DOOR:
- case E_BLOCK_IRON_DOOR:
- case E_BLOCK_REDSTONE_REPEATER_OFF:
- case E_BLOCK_REDSTONE_REPEATER_ON:
- case E_BLOCK_POWERED_RAIL:
- {
- return true;
- }
- default: return false;
- }
- }
-
- /** Returns if a block has the potential to output power */
- inline static bool IsPotentialSource(BLOCKTYPE Block)
- {
- switch (Block)
- {
- case E_BLOCK_DETECTOR_RAIL:
- case E_BLOCK_DAYLIGHT_SENSOR:
- case E_BLOCK_WOODEN_BUTTON:
- case E_BLOCK_STONE_BUTTON:
- case E_BLOCK_REDSTONE_WIRE:
- case E_BLOCK_REDSTONE_TORCH_ON:
- case E_BLOCK_LEVER:
- case E_BLOCK_REDSTONE_REPEATER_ON:
- case E_BLOCK_BLOCK_OF_REDSTONE:
- case E_BLOCK_ACTIVE_COMPARATOR:
- {
- return true;
- }
- default: return false;
- }
- }
- /** Returns if a block is any sort of redstone device */
- inline static bool IsRedstone(BLOCKTYPE Block)
- {
- switch (Block)
- {
- // All redstone devices, please alpha sort
- case E_BLOCK_ACTIVATOR_RAIL:
- case E_BLOCK_ACTIVE_COMPARATOR:
- case E_BLOCK_BLOCK_OF_REDSTONE:
- case E_BLOCK_COMMAND_BLOCK:
- case E_BLOCK_DETECTOR_RAIL:
- case E_BLOCK_DISPENSER:
- case E_BLOCK_DAYLIGHT_SENSOR:
- case E_BLOCK_DROPPER:
- case E_BLOCK_FENCE_GATE:
- case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE:
- case E_BLOCK_HOPPER:
- case E_BLOCK_INACTIVE_COMPARATOR:
- case E_BLOCK_IRON_DOOR:
- case E_BLOCK_LEVER:
- case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE:
- case E_BLOCK_NOTE_BLOCK:
- case E_BLOCK_POWERED_RAIL:
- case E_BLOCK_REDSTONE_LAMP_OFF:
- case E_BLOCK_REDSTONE_LAMP_ON:
- case E_BLOCK_REDSTONE_REPEATER_OFF:
- case E_BLOCK_REDSTONE_REPEATER_ON:
- case E_BLOCK_REDSTONE_TORCH_OFF:
- case E_BLOCK_REDSTONE_TORCH_ON:
- case E_BLOCK_REDSTONE_WIRE:
- case E_BLOCK_STICKY_PISTON:
- case E_BLOCK_STONE_BUTTON:
- case E_BLOCK_STONE_PRESSURE_PLATE:
- case E_BLOCK_TNT:
- case E_BLOCK_TRAPDOOR:
- case E_BLOCK_TRIPWIRE_HOOK:
- case E_BLOCK_WOODEN_BUTTON:
- case E_BLOCK_WOODEN_DOOR:
- case E_BLOCK_WOODEN_PRESSURE_PLATE:
- case E_BLOCK_PISTON:
- {
- return true;
- }
- default: return false;
- }
- }
-};
+} ;
diff --git a/src/WebAdmin.cpp b/src/WebAdmin.cpp
index e6a5a01b3..e88de5947 100644
--- a/src/WebAdmin.cpp
+++ b/src/WebAdmin.cpp
@@ -42,6 +42,7 @@ public:
cWebAdmin::cWebAdmin(void) :
m_IsInitialized(false),
+ m_IsRunning(false),
m_TemplateScript("<webadmin_template>")
{
}
@@ -52,29 +53,26 @@ cWebAdmin::cWebAdmin(void) :
cWebAdmin::~cWebAdmin()
{
- if (m_IsInitialized)
- {
- LOGD("Stopping WebAdmin...");
- }
+ ASSERT(!m_IsRunning); // Was the HTTP server stopped properly?
}
-void cWebAdmin::AddPlugin( cWebPlugin * a_Plugin )
+void cWebAdmin::AddPlugin(cWebPlugin * a_Plugin)
{
- m_Plugins.remove( a_Plugin );
- m_Plugins.push_back( a_Plugin );
+ m_Plugins.remove(a_Plugin);
+ m_Plugins.push_back(a_Plugin);
}
-void cWebAdmin::RemovePlugin( cWebPlugin * a_Plugin )
+void cWebAdmin::RemovePlugin(cWebPlugin * a_Plugin)
{
- m_Plugins.remove( a_Plugin );
+ m_Plugins.remove(a_Plugin);
}
@@ -87,7 +85,8 @@ bool cWebAdmin::Init(void)
{
LOGWARN("Regenerating webadmin.ini, all settings will be reset");
m_IniFile.AddHeaderComment(" This file controls the webadmin feature of MCServer");
- m_IniFile.AddHeaderComment(" Username format: [User:*username*] | Password format: Password=*password*; for example:");
+ m_IniFile.AddHeaderComment(" Username format: [User:*username*]");
+ m_IniFile.AddHeaderComment(" Password format: Password=*password*; for example:");
m_IniFile.AddHeaderComment(" [User:admin]");
m_IniFile.AddHeaderComment(" Password=admin");
}
@@ -134,7 +133,24 @@ bool cWebAdmin::Start(void)
m_TemplateScript.Close();
}
- return m_HTTPServer.Start(*this);
+ m_IsRunning = m_HTTPServer.Start(*this);
+ return m_IsRunning;
+}
+
+
+
+
+
+void cWebAdmin::Stop(void)
+{
+ if (!m_IsRunning)
+ {
+ return;
+ }
+
+ LOGD("Stopping WebAdmin...");
+ m_HTTPServer.Stop();
+ m_IsRunning = false;
}
diff --git a/src/WebAdmin.h b/src/WebAdmin.h
index 3eb807640..a2a07a543 100644
--- a/src/WebAdmin.h
+++ b/src/WebAdmin.h
@@ -56,13 +56,13 @@ struct HTTPRequest
AString Username;
// tolua_end
- /// Parameters given in the URL, after the questionmark
+ /** Parameters given in the URL, after the questionmark */
StringStringMap Params; // >> EXPORTED IN MANUALBINDINGS <<
- /// Parameters posted as a part of a form - either in the URL (GET method) or in the body (POST method)
+ /** Parameters posted as a part of a form - either in the URL (GET method) or in the body (POST method) */
StringStringMap PostParams; // >> EXPORTED IN MANUALBINDINGS <<
- /// Same as PostParams
+ /** Same as PostParams */
FormDataMap FormData; // >> EXPORTED IN MANUALBINDINGS <<
} ; // tolua_export
@@ -107,14 +107,17 @@ public:
cWebAdmin(void);
virtual ~cWebAdmin();
- /// Initializes the object. Returns true if successfully initialized and ready to start
+ /** Initializes the object. Returns true if successfully initialized and ready to start */
bool Init(void);
- /// Starts the HTTP server taking care of the admin. Returns true if successful
+ /** Starts the HTTP server taking care of the admin. Returns true if successful */
bool Start(void);
+
+ /** Stops the HTTP server, if it was started. */
+ void Stop(void);
- void AddPlugin( cWebPlugin* a_Plugin );
- void RemovePlugin( cWebPlugin* a_Plugin );
+ void AddPlugin(cWebPlugin * a_Plugin);
+ void RemovePlugin(cWebPlugin * a_Plugin);
// TODO: Convert this to the auto-locking callback mechanism used for looping players in worlds and such
PluginList GetPlugins() const { return m_Plugins; } // >> EXPORTED IN MANUALBINDINGS <<
@@ -123,13 +126,13 @@ public:
sWebAdminPage GetPage(const HTTPRequest & a_Request);
- /// Returns the contents of the default page - the list of plugins and players
+ /** Returns the contents of the default page - the list of plugins and players */
AString GetDefaultPage(void);
- /// Returns the prefix needed for making a link point to the webadmin root from the given URL ("../../../webadmin"-style)
+ /** Returns the prefix needed for making a link point to the webadmin root from the given URL ("../../../webadmin"-style) */
AString GetBaseURL(const AString & a_URL);
- /// Escapes text passed into it, so it can be embedded into html.
+ /** Escapes text passed into it, so it can be embedded into html. */
static AString GetHTMLEscapedString(const AString & a_Input);
AString GetIPv4Ports(void) const { return m_PortsIPv4; }
@@ -137,21 +140,21 @@ public:
// tolua_end
- /// Returns the prefix needed for making a link point to the webadmin root from the given URL ("../../../webadmin"-style)
+ /** Returns the prefix needed for making a link point to the webadmin root from the given URL ("../../../webadmin"-style) */
AString GetBaseURL(const AStringVector& a_URLSplit);
protected:
- /// Common base class for request body data handlers
+ /** Common base class for request body data handlers */
class cRequestData
{
public:
virtual ~cRequestData() {} // Force a virtual destructor in all descendants
- /// Called when a new chunk of body data is received
+ /** Called when a new chunk of body data is received */
virtual void OnBody(const char * a_Data, int a_Size) = 0;
} ;
- /// The body handler for requests in the "/webadmin" and "/~webadmin" paths
+ /** The body handler for requests in the "/webadmin" and "/~webadmin" paths */
class cWebadminRequestData :
public cRequestData,
public cHTTPFormParser::cCallbacks
@@ -182,10 +185,13 @@ protected:
} ;
- /// Set to true if Init() succeeds and the webadmin isn't to be disabled
+ /** Set to true if Init() succeeds and the webadmin isn't to be disabled */
bool m_IsInitialized;
+
+ /** Set to true if Start() succeeds in starting the server, reset back to false in Stop(). */
+ bool m_IsRunning;
- /// The webadmin.ini file, used for the settings and allowed logins
+ /** The webadmin.ini file, used for the settings and allowed logins */
cIniFile m_IniFile;
PluginList m_Plugins;
@@ -193,19 +199,19 @@ protected:
AString m_PortsIPv4;
AString m_PortsIPv6;
- /// The Lua template script to provide templates:
+ /** The Lua template script to provide templates: */
cLuaState m_TemplateScript;
- /// The HTTP server which provides the underlying HTTP parsing, serialization and events
+ /** The HTTP server which provides the underlying HTTP parsing, serialization and events */
cHTTPServer m_HTTPServer;
AString GetTemplate(void);
- /// Handles requests coming to the "/webadmin" or "/~webadmin" URLs
+ /** Handles requests coming to the "/webadmin" or "/~webadmin" URLs */
void HandleWebadminRequest(cHTTPConnection & a_Connection, cHTTPRequest & a_Request);
- /// Handles requests for the root page
+ /** Handles requests for the root page */
void HandleRootRequest(cHTTPConnection & a_Connection, cHTTPRequest & a_Request);
// cHTTPServer::cCallbacks overrides:
diff --git a/src/World.cpp b/src/World.cpp
index 04dda0d65..d2523b0a5 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -29,8 +29,9 @@
#include "Simulator/FluidSimulator.h"
#include "Simulator/FireSimulator.h"
#include "Simulator/NoopFluidSimulator.h"
+#include "Simulator/NoopRedstoneSimulator.h"
#include "Simulator/SandSimulator.h"
-#include "Simulator/RedstoneSimulator.h"
+#include "Simulator/IncrementalRedstoneSimulator.h"
#include "Simulator/VaporizeFluidSimulator.h"
// Mobs:
@@ -247,11 +248,13 @@ cWorld::cWorld(const AString & a_WorldName) :
m_SkyDarkness(0),
m_Weather(eWeather_Sunny),
m_WeatherInterval(24000), // Guaranteed 1 day of sunshine at server start :)
+ m_Scoreboard(this),
m_GeneratorCallbacks(*this),
m_TickThread(*this),
m_Scoreboard(this),
m_bCommandBlocksEnabled(false),
m_bUseChatPrefixes(true)
+ m_TickThread(*this)
{
LOGD("cWorld::cWorld(\"%s\")", a_WorldName.c_str());
@@ -599,12 +602,11 @@ void cWorld::Start(void)
m_LavaSimulator = InitializeFluidSimulator(IniFile, "Lava", E_BLOCK_LAVA, E_BLOCK_STATIONARY_LAVA);
m_SandSimulator = new cSandSimulator(*this, IniFile);
m_FireSimulator = new cFireSimulator(*this, IniFile);
- m_RedstoneSimulator = new cRedstoneSimulator(*this);
+ m_RedstoneSimulator = InitializeRedstoneSimulator(IniFile);
- // Water and Lava simulators get registered in InitializeFluidSimulator()
+ // Water, Lava and Redstone simulators get registered in their initialize function.
m_SimulatorManager->RegisterSimulator(m_SandSimulator, 1);
m_SimulatorManager->RegisterSimulator(m_FireSimulator, 1);
- m_SimulatorManager->RegisterSimulator(m_RedstoneSimulator, 1);
m_Lighting.Start(this);
m_Storage.Start(this, m_StorageSchema, m_StorageCompressionFactor );
@@ -2874,6 +2876,36 @@ void cWorld::TabCompleteUserName(const AString & a_Text, AStringVector & a_Resul
+cRedstoneSimulator * cWorld::InitializeRedstoneSimulator(cIniFile & a_IniFile)
+{
+ AString SimulatorName = a_IniFile.GetValueSet("Physics", "RedstoneSimulator", "");
+
+ if (SimulatorName.empty())
+ {
+ LOGWARNING("[Physics] RedstoneSimulator not present or empty in %s, using the default of \"incremental\".", GetIniFileName().c_str());
+ SimulatorName = "incremental";
+ }
+
+ cRedstoneSimulator * res = NULL;
+
+ if (NoCaseCompare(SimulatorName, "incremental") == 0)
+ {
+ res = new cIncrementalRedstoneSimulator(*this);
+ }
+ else if (NoCaseCompare(SimulatorName, "noop") == 0)
+ {
+ res = new cRedstoneNoopSimulator(*this);
+ }
+
+ m_SimulatorManager->RegisterSimulator(res, 1);
+
+ return res;
+}
+
+
+
+
+
cFluidSimulator * cWorld::InitializeFluidSimulator(cIniFile & a_IniFile, const char * a_FluidName, BLOCKTYPE a_SimulateBlock, BLOCKTYPE a_StationaryBlock)
{
AString SimulatorNameKey;
diff --git a/src/World.h b/src/World.h
index a2385fca4..0174be03b 100644
--- a/src/World.h
+++ b/src/World.h
@@ -875,6 +875,9 @@ private:
/** Creates a new fluid simulator, loads its settings from the inifile (a_FluidName section) */
cFluidSimulator * InitializeFluidSimulator(cIniFile & a_IniFile, const char * a_FluidName, BLOCKTYPE a_SimulateBlock, BLOCKTYPE a_StationaryBlock);
+
+ /** Creates a new redstone simulator.*/
+ cRedstoneSimulator * InitializeRedstoneSimulator(cIniFile & a_IniFile);
}; // tolua_export