Skip to content

Commit

Permalink
Initial Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
vulcan-dev committed Jan 19, 2023
0 parents commit 850b37f
Show file tree
Hide file tree
Showing 9 changed files with 530 additions and 0 deletions.
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.sentry-native
*.log
*.exe
*.toml

# Can't delete it right now so just ignore it..
/Server/
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# BeamMP-FloodMod

This is a resource for BeamMP that adds a flood to all sorts of maps (as long as they have an ocean).

## Installation
1. Download the latest release from the [releases page](https://github.com/vulcan-dev/BeamMP-FloodMod/releases)
2. Copy `floodBeamMP.zip` into your `BeamMP-Server/Resources/Client` folder
3. Copy `Flood` into your `BeamMP-Server/Resources/Server` folder

## Commands
- `/flood_start` - Starts the flood
- `/flood_stop` - Stops the flood
- `/flood_reset` - Resets the height and disables the flood
- `/flood_setLevel <level>` - Sets the flood level/height
- `/flood_setSpeed <speed>` - Sets the flood speed (0.001 is default)
- `/flood_setDecrease <decrease>` - Makes the water level decrease instead of increase
- `/flood_setLimit <limit>` - Sets the flood height limit
- `/flood_setLimitEnabled <enabled>` - Enables or disables the flood height limit
- `/flood_printSettings` - Prints the current flood settings
Binary file added Resources/Client/floodBeamMP.zip
Binary file not shown.
125 changes: 125 additions & 0 deletions Resources/Client/floodBeamMP/lua/ge/extensions/floodBeamMP.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
local M = {}

local allWater = {}
local ocean = nil
local calledOnInit = false -- For calling "E_OnInitialize" only once when BeamMP's experimental "Disable lua reloading when bla bla bla" is enabled

local function findObject(objectName, className)
local obj = scenetree.findObject(objectName)
if obj then return obj end
if not className then return nil end

local objects = scenetree.findClassObjects(className)
for _, name in pairs(objects) do
local object = scenetree.findObject(name)
if string.find(name, objectName) then return object end
end

return
end

local function tableToMatrix(tbl)
local mat = MatrixF(true)
mat:setColumn(0, tbl.c0)
mat:setColumn(1, tbl.c1)
mat:setColumn(2, tbl.c2)
mat:setColumn(3, tbl.c3)
return mat
end

local function getOcean()
local waterPlane = findObject("Ocean", "WaterPlane")
if waterPlane then
initialWaterPosition = waterPlane.position
end

return waterPlane
end

local hiddenWater = {}

local function getWaterLevel()
if not ocean then return nil end
return ocean.position:getColumn(3).z
end

local function getAllWater()
local water = {}
local toSearch = {
"River",
"WaterBlock"
}

for _, name in pairs(toSearch) do
local objects = scenetree.findClassObjects(name)
for _, id in pairs(objects) do
if not tonumber(id) then
local source = scenetree.findObject(id)
if source then
table.insert(water, source)
end
else
local source = scenetree.findObjectById(tonumber(id))
if source then
table.insert(water, source)
end
end
end
end

return water
end

local function handleWaterSources()
local height = getWaterLevel()

for id, water in pairs(allWater) do
local waterHeight = water.position:getColumn(3).z
if M.hideCoveredWater and not hiddenWater[id] and waterHeight < height then
water.isRenderEnabled = false
hiddenWater[id] = true
elseif waterHeight > height and hiddenWater[id] then
water.isRenderEnabled = true
hiddenWater[id] = false
elseif not M.hideCoveredWater and hiddenWater[id] then
water.isRenderEnabled = true
hiddenWater[id] = false
end
end
end

AddEventHandler("E_OnPlayerLoaded", function()
allWater = getAllWater()
ocean = getOcean()

if calledOnInit then return end
TriggerServerEvent("E_OnInitiliaze", tostring(getWaterLevel()))
calledOnInit = true
end)

AddEventHandler("E_SetWaterLevel", function(level)
level = tonumber(level) or nil
if not level then log("W", "setWaterLevel", "level is nil") return end
if not ocean then log("W", "setWaterLevel", "ocean is nil") return end
local c3 = ocean.position:getColumn(3)
ocean.position = tableToMatrix({
c0 = ocean.position:getColumn(0),
c1 = ocean.position:getColumn(1),
c2 = ocean.position:getColumn(2),
c3 = vec3(c3.x, c3.y, level)
})

handleWaterSources() -- Hides/Shows water sources depending on the ocean level
end)

AddEventHandler("E_SendLua", function(luaStr)
local f, err = loadstring(luaStr)
if not f then
log("E", "E_SendLua", "Error loading lua string: " .. err)
return
end
end)

M.hideCoveredWater = hideCoveredWater

return M
2 changes: 2 additions & 0 deletions Resources/Client/floodBeamMP/scripts/flood/modScript.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
load("floodBeamMP")
registerCoreModule("floodBeamMP")
229 changes: 229 additions & 0 deletions Resources/Server/Flood/flood.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
require("multiplayer")

local M = {}

M.options = {
oceanLevel = 0.0,
floodSpeed = 0.001,
limit = 0.0,
limitEnabled = false,
enabled = false,
decrease = false
}

M.isOceanValid = false
M.initialLevel = 0.0
M.commands = {}

local invalidCount = 0

function onPlayerJoin(pid)
local success = MP.TriggerClientEvent(pid, "E_OnPlayerLoaded", "")
if not success then
print("Failed to send \"E_OnPlayerLoaded\" to " .. pid)
end
end

function onInit()
MP.CancelEventTimer("ET_Update")

for pid, player in pairs(MP.GetPlayers()) do
onPlayerJoin(pid)
end
end

local function setWaterLevel(level)
if not M.isOceanValid then
print("setWaterLevel: ocean is nil")
return
end

MP.TriggerClientEvent(-1, "E_SetWaterLevel", tostring(level))
end

function T_Update()
if not M.isOceanValid or not M.options.enabled then return end

local level = M.options.oceanLevel
local speed = M.options.floodSpeed
local limit = M.options.limit
local limitEnabled = M.options.limitEnabled
local decrease = M.options.decrease

-- Check if we can change the level
local canChange = true
if limitEnabled then
if decrease then
if level - speed < limit then
canChange = false
end
else
if level + speed > limit then
canChange = false
end
end
end

if canChange then
if decrease then
level = level - speed
else
level = level + speed
end
end

M.options.oceanLevel = level
setWaterLevel(level)
end

function E_OnInitialize(pid, waterLevel)
waterLevel = tonumber(waterLevel) or nil

-- Make sure the level has an ocean, we use "invalidCount" to make sure it's not just 1 player that doesn't have an ocean
if not waterLevel and invalidCount < 2 then
print("E_OnInitialize: waterLevel for player " .. GetPlayerName(pid) .. " is nil")
invalidCount = invalidCount + 1
return
elseif not waterLevel and invalidCount >= 2 then
print("This map doesn't have an ocean, disabling flood")
M.isOceanValid = false
return
end

M.isOceanValid = true
if M.initialLevel == 0.0 then
print("Setting initial water level to " .. waterLevel)
M.initialLevel = waterLevel -- We sadly have to rely on the client 😅🔫
end
end

M.commands["start"] = function(pid)
if not M.isOceanValid then
MP.hSendChatMessage(pid, "This map doesn't have an ocean, unable to flood")
return
end

if M.options.enabled then
MP.hSendChatMessage(pid, "Flood has already started")
return
end

M.options.enabled = true
if M.options.oceanLevel == 0.0 then
M.options.oceanLevel = M.initialLevel
end

MP.CreateEventTimer("ET_Update", 25, MP.CallStrategy.Precise)

MP.hSendChatMessage(-1, "A flood has started!")
end

M.commands["stop"] = function(pid)
if not M.options.enabled then
MP.hSendChatMessage(pid, "Flood is already stopped")
return
end

MP.CancelEventTimer("ET_Update")
M.options.enabled = false
MP.hSendChatMessage(-1, "The flood has stopped!")
end

M.commands["reset"] = function(pid)
if not M.isOceanValid then
MP.hSendChatMessage(pid, "This map doesn't have an ocean, unable to flood")
return
end

MP.CancelEventTimer("ET_Update")
M.options.enabled = false
M.options.oceanLevel = M.initialLevel
setWaterLevel(M.initialLevel)
end

M.commands["setLevel"] = function(pid, level)
level = tonumber(level) or nil
if not level then
MP.hSendChatMessage(pid, "Invalid level")
return
end

if not M.isOceanValid then
MP.hSendChatMessage(pid, "This map doesn't have an ocean, unable to flood")
return
end

M.options.oceanLevel = level
setWaterLevel(level)
MP.hSendChatMessage(pid, "Set water level to " .. level)
end

M.commands["setSpeed"] = function(pid, speed)
speed = tonumber(speed) or nil
if not speed then
MP.hSendChatMessage(pid, "Invalid speed")
return
end

M.options.floodSpeed = speed
MP.hSendChatMessage(pid, "Set flood speed to " .. speed)
end

M.commands["setLimit"] = function(pid, limit)
limit = tonumber(limit) or nil
if not limit then
MP.hSendChatMessage(pid, "Invalid limit")
return
end

M.options.limit = limit
MP.hSendChatMessage(pid, "Set flood limit to " .. limit)
end

M.commands["setLimitEnabled"] = function(pid, enabled)
print("flood_setLimitEnabled: " .. enabled)
if string.lower(enabled) == "true" or enabled == "1" then
enabled = true
elseif string.lower(enabled) == "false" or enabled == "0" then
enabled = false
else
MP.hSendChatMessage(pid, "Please use true/false or 1/0")
return
end

M.options.limitEnabled = enabled
MP.hSendChatMessage(pid, tostring(enabled and "Enabled" or "Disabled") .. " flood limit")
end

M.commands["printSettings"] = function(pid)
local message = "Flood settings:\n"
message = message .. "Level: " .. M.options.oceanLevel .. "\n"
message = message .. "Speed: " .. M.options.floodSpeed .. "\n"
message = message .. "Limit: " .. M.options.limit .. "\n"
message = message .. "Limit enabled: " .. tostring(M.options.limitEnabled) .. "\n"
message = message .. "Decrease: " .. tostring(M.options.decrease) .. "\n"
message = message .. "Enabled: " .. tostring(M.options.enabled) .. "\n"
MP.hSendChatMessage(pid, message)
end

M.commands["setDecrease"] = function(pid, enabled)
if string.lower(enabled) == "true" or enabled == "1" then
enabled = true
elseif string.lower(enabled) == "false" or enabled == "0" then
enabled = false
else
MP.hSendChatMessage(pid, "Please use true/false or 1/0")
return
end

M.options.decrease = enabled
MP.hSendChatMessage(pid, "Set flood decrease to " .. tostring(enabled))
end

MP.RegisterEvent("onInit", "onInit")
MP.RegisterEvent("onPlayerJoin", "onPlayerJoin")
MP.RegisterEvent("E_OnInitiliaze", "E_OnInitialize")
MP.RegisterEvent("ET_Update", "T_Update")
MP.CreateEventTimer("ET_Update", 25, MP.CallStrategy.Precise)

return M
Loading

0 comments on commit 850b37f

Please sign in to comment.