local WaterPlugin = {} WaterPlugin.__index = WaterPlugin function WaterPlugin:new() local t = {} setmetatable(t, WaterPlugin) local w = Lua__cPlugin:new() tolua.setpeer(w, t) w:tolua__set_instance(w) return w end function WaterPlugin:OnDisable() Log( Plugin:GetName() .. " v." .. Plugin:GetVersion() .. " is shutting down..." ) end function WaterPlugin:Initialize() self:SetName( "Water" ) self:SetVersion( 1 ) PluginManager = cRoot:Get():GetPluginManager() PluginManager:AddHook( self, cPluginManager.E_PLUGIN_TICK ) PluginManager:AddHook( self, cPluginManager.E_PLUGIN_BLOCK_DIG ) PluginManager:AddHook( self, cPluginManager.E_PLUGIN_BLOCK_PLACE ) self.WaterBlocks = {}; self.WaterBlocks = {}; Log( "Initialized " .. self:GetName() .. " v." .. self:GetVersion() ) self.NumTicks = 0; return true end function IsFreeForWater(block) return block == E_BLOCK_AIR or block == E_BLOCK_TORCH or block == E_BLOCK_MINECART_TRACKS or block == E_BLOCK_REDSTONE_TORCH_ON or block == E_BLOCK_REDSTONE_TORCH_OFF; end function WaterPlugin:OnBlockPlace( PacketData, Player ) local X = PacketData.m_PosX local Y = PacketData.m_PosY local Z = PacketData.m_PosZ X, Y, Z = AddDirection( X, Y, Z, PacketData.m_Direction ) local t = PacketData.m_ItemType; -- the type of item used to call the place command Log("water: " .. X .. "," .. Y .. "," .. Z .. " -- adding due to Place... " .. t); local World = cRoot:Get():GetWorld(); if(t == 326) then -- water bucket World:SetBlock(X, Y, Z, E_BLOCK_WATER, 0); elseif(t == 9) then World:SetBlock(X, Y, Z, E_BLOCK_WATER, 0); end self:AddSurroundings(X, Y, Z); self:AddBlock(X, Y, Z); return false end function WaterPlugin:AddSurroundings(X, Y, Z) local level_points = { {X-1, Y, Z}, {X+1, Y, Z}, {X, Y, Z-1}, {X, Y, Z+1}, {X, Y+1, Z}, {X, Y-1, Z}, }; for key,val in pairs(level_points) do self:AddBlock(val[1], val[2], val[3]); end end function WaterPlugin:AddBlock(X, Y, Z) local World = cRoot:Get():GetWorld(); local t = World:GetBlock(X, Y, Z); if(t == E_BLOCK_WATER or t == E_BLOCK_STATIONARY_WATER) then local found = false; for key,val in pairs(self.WaterBlocks) do if(val[1] == X and val[2] == Y and val[3] == Z) then found = true; Log("addblock found"); break; end end end if(not found) then Log("addblock adding"); table.insert(self.WaterBlocks, {X, Y, Z}); end end function WaterPlugin:OnBlockDig( PacketData, Player ) local X = PacketData.m_PosX local Y = PacketData.m_PosY local Z = PacketData.m_PosZ if(PacketData.m_Status == 3) then -- block broken Log("water: " .. X .. "," .. Y .. "," .. Z .. " -- adding due to dig... status is: " .. PacketData.m_Status); self:AddSurroundings(X, Y, Z); end return false end function WaterPlugin:Tick( DeltaTime ) if( self.NumTicks < 10 ) then -- Only spread every 50 ticks, to make sure it doesnt happen too fast self.NumTicks = self.NumTicks + 1 return end local debug = true; self.NumTicks = 0 local World = cRoot:Get():GetWorld() local OldBlocks = self.WaterBlocks; self.WaterBlocks = {}; for key,val in pairs(OldBlocks) do local X = val[1] local Y = val[2] local Z = val[3] local t = World:GetBlock(X, Y, Z); Log("processing: " .. X .. "," .. Y .. "," .. Z .. " -- " .. t); if(t == E_BLOCK_WATER) then local isFed = false; local f = World:GetBlockMeta(X, Y, Z); local f2 = f; if(f == 8) then local t2 = World:GetBlock(X, Y+1, Z); if(t2 == E_BLOCK_WATER) then isFed = true; local t3 = World:GetBlock(X, Y-1, Z); local f3 = World:GetBlockMeta(X, Y-1, Z); if(t3 == E_BLOCK_WATER and f3 == 8) then -- I'm falling, don't spread sideways else f = 0; end end elseif(f == 0) then isFed = true; else f2 = GetMaximumWaterAround(X, Y, Z); if(f2 < f) then isFed = true; end end if(isFed) then Log(" isFed"); local down = World:GetBlock(X, Y-1, Z); if(IsFreeForWater(down)) then Log(" down"); World:SetBlock(X, Y-1, Z, E_BLOCK_WATER, 8); self:AddBlock(X, Y-1, Z); else Log(" around"); if(f == 8) then -- Im falling elseif(f2+1 < f) then World:SetBlock(X, Y, Z, E_BLOCK_WATER, f2+1); self:AddBlock(X, Y, Z); elseif(f < 7) then Log(" enough power"); local points = GetLowestPoints(X, Y, Z); for k,v in pairs(points) do local t2 = World:GetBlock(v[1], v[2], v[3]); if(t2 ~= E_BLOCK_WATER) then if(v[2] == Y) then World:SetBlock(v[1], v[2], v[3], E_BLOCK_WATER, f+1); else World:SetBlock(v[1], v[2], v[3], E_BLOCK_WATER, 8); end self:AddBlock(v[1], v[2], v[3]); else -- is water local f3 = World:GetBlockMeta(v[1], v[2], v[3]); if(f3 ~= 8 and f3 > f+1) then self:AddBlock(v[1], v[2], v[3]); end end end end end end end end end function GetMaximumWaterAround(X, Y, Z) local mx = 8; local level_points = { {X-1, Y, Z}, {X+1, Y, Z}, {X, Y, Z-1}, {X, Y, Z+1}, }; local World = cRoot:Get():GetWorld(); for key,val in pairs(level_points) do local t = World:GetBlock(val[1], val[2], val[3]); if(t == E_BLOCK_STATIONARY_WATER) then mx = 0; break; elseif(t == E_BLOCK_WATER) then local f = World:GetBlockMeta(val[1], val[2], val[3]); if(f < mx) then mx = f; elseif(f == 8) then mx = 0; end if(mx == 0) then break; end end end return mx; end function GetLowestPoints(X, Y, Z) local World = cRoot:Get():GetWorld() local t = World:GetBlock(X, Y-1, Z); local points = {}; if(IsFreeForWater(t)) then table.insert(points, {X, Y-1, Z}); return points; end local lower_points = { {X-1, Y-1, Z}, {X+1, Y-1, Z}, {X, Y-1, Z-1}, {X, Y-1, Z+1}, }; local waterFound = false; for key,val in pairs(lower_points) do local t = World:GetBlock(val[1], val[2], val[3]); local t2 = World:GetBlock(val[1], Y, val[3]); if(IsFreeForWater(t) and IsFreeForWater(t2)) then table.insert(points, val); val[2] = Y; table.insert(points, val); elseif(t2 == E_BLOCK_WATER and (IsFreeForWater(t) or t == E_BLOCK_WATER)) then waterFound = true; end end if(#points == 0 and not waterFound) then local level_points = { {X-1, Y, Z}, {X+1, Y, Z}, {X, Y, Z-1}, {X, Y, Z+1}, }; for key,val in pairs(level_points) do local t = World:GetBlock(val[1], val[2], val[3]); if(IsFreeForWater(t) or t == E_BLOCK_WATER) then table.insert(points, val); end end end return points; end Plugin = WaterPlugin:new() cRoot:Get():GetPluginManager():AddPlugin( Plugin )