Its a bug where the player can hold space and jump forever essentially. (at the top of water)
Seems like a very nice module. I modified it to use CollectionService exclusivly and made it so tags can be added during runtime (and not have a single tag beforehand). However, I noticed one little error with the module
Where there is the code for detecting when a tag is added or removed, it listens to the “water_parts” tag instead of using the tag variable. This means that for people who use collection service and a custom tag, if a tag is added to a part during runtime, the script will not detect it
Thanks for pointing that out. It is fixed now.
Important update: The system now works with gamepad. It should have worked before but since I couldn’t test it I wasn’t able to know.
This system doesn’t seem to be working as of now. Similar issue to the infinite jumping bug but in my case the swim animations don’t start at all. It just allows the player to fly by holding space after touching a water part. Even while outside of the water part.
Reverted to a previous version that didn’t have this bug. The only change is that the previous version doesn’t allow jumping for xbox. It will stay like that until I find what is causing the problem on the newer one.
“Go read the whole post you lazy duck” i liked this line. its funny.
I did tweak on it on the script, it’s not the best one since it heavily relies on timing but i hope @gpm231 can fix this properly and know the concept of the rework I did. I only change the gOut to have a debounce on the function and instead of gOut i used the 1.0 version get goOutOfWater() function on it. I havent tested it on mobile or live server, but on pc and studio it works fine so far. Heres the new code for HighperformanceWater:
--[[
Script made by gpm231 on 2022
--For info about this check the devforum post --> https://devforum.roblox.com/t/high-performance-water-swimmable-part-20/2038483
--Contact:
-Roblox: gpm231
-Twitter: @gpm231RBLX
-Discord: gpm231#9505
--]]
if not game:IsLoaded() then --wait for assets
game.Loaded:Wait()
end
local userInputService = game:GetService("UserInputService")
local isTouchScreen = userInputService.TouchEnabled
local swimModule = require(script:WaitForChild("Libraries"):WaitForChild("SwimModule"))
local zonePlus = require(script:WaitForChild("Libraries"):WaitForChild("Zone"))
local lightingModule = require(script:WaitForChild("Libraries"):WaitForChild("UnderwaterLighting"))
local plr = game:GetService("Players").LocalPlayer
local char = plr.Character or plr.CharacterAdded:Wait()
repeat task.wait() until char:FindFirstChildOfClass("Humanoid")
local hum = char:FindFirstChildOfClass("Humanoid")
local hrp = char:WaitForChild("HumanoidRootPart")
local tag = script.CollectionServiceTag.Value
local folder = script.PartFolder.Value
local container = folder or game:GetService("CollectionService"):GetTagged(tag)
if typeof(container) == "table" then if #container < 1 then container = nil end end
if not container then error('Please set a folder that contains the parts for the player to swim in OR tag your parts using collection service') end
local zone = zonePlus.new(container)
local gotOut = false
local defaultForce = hrp.AssemblyMass * workspace.Gravity
local tapCon --tap event connection
local debounce = false --for mobile devices to allow jumping out of water
local function folderChanged() --if you want to update the water parts this tracks the change
zone = zonePlus.new(container)
end
if script.PartFolder.Value then
container.ChildAdded:Connect(folderChanged)
container.ChildRemoved:Connect(folderChanged)
else
game:GetService("CollectionService"):GetInstanceAddedSignal(script.CollectionServiceTag.Value):Connect(folderChanged)
game:GetService("CollectionService"):GetInstanceRemovedSignal(script.CollectionServiceTag.Value):Connect(folderChanged)
end
local function getKeycodesPressed()
local data = {}
local a = userInputService:GetKeysPressed()
for _, obj in a do
table.insert(data, obj.KeyCode)
end
return data
end
local function goOutOfWater()
swimModule:Stop()
hum:SetStateEnabled(Enum.HumanoidStateType.Jumping, true)
hum:ChangeState(Enum.HumanoidStateType.Jumping)
hum:SetStateEnabled(Enum.HumanoidStateType.GettingUp, true)
--[[
hum:SetStateEnabled(Enum.HumanoidStateType.Jumping, false)
hum:SetStateEnabled(Enum.HumanoidStateType.GettingUp, false)
]]
wait(0.8)
end
local gOutDB = false --modified by me
local con = game:GetService("RunService").Heartbeat:Connect(function()
if debounce then return end
if tapCon then
tapCon:Disconnect()
tapCon = nil
end
local UpperDetectorPos = hrp.CFrame:ToWorldSpace(CFrame.new(0, 1, -0.75))
local LowerDetectorPos = hrp.CFrame:ToWorldSpace(CFrame.new(0, -2.572, -0.75))
local HeadDetectorPos = hrp.CFrame:ToWorldSpace(CFrame.new(0, 1.322, -0.75))
local isUpperIn = zone:findPoint(UpperDetectorPos)
local isLowerIn = zone:findPoint(LowerDetectorPos)
local isHeadIn = zone:findPoint(HeadDetectorPos)
local isCameraIn = zone:findPoint(workspace.CurrentCamera.CFrame.Position)
--Getting out of water
local function gOut()
if not isTouchScreen then
swimModule:GetOut()
swimModule:Stop()
else
for i = 1, 20 do --weird stuff mobile needs
swimModule:GetOut()
swimModule:Stop()
end
debounce = true
task.wait(0.25) --weird stuff mobile needs
debounce = false
end
end
if table.find(getKeycodesPressed(), Enum.KeyCode.Space or table.find(getKeycodesPressed(), Enum.KeyCode.ButtonA)) and not isHeadIn and isLowerIn then
if gOutDB == false then --modified by me
gOutDB = true
goOutOfWater()
--gOut()
wait(.4)
gOutDB = false
end
end
--Exception handlers
if isUpperIn and isLowerIn then
swimModule:Start()
if gotOut then --for when the player goes back into the water after jumping out
swimModule:CreateAntiGrav()
gotOut = false
end
elseif not isUpperIn and not isLowerIn then
swimModule:Stop()
elseif not isUpperIn and isLowerIn then
swimModule:ClearAntiGrav()
gotOut = true
end
--Going up forces
if table.find(getKeycodesPressed(), Enum.KeyCode.Space) or table.find(getKeycodesPressed(), Enum.KeyCode.ButtonA) then
local force = hrp:FindFirstChildOfClass("VectorForce")
if force then
force.Force = Vector3.new(0, defaultForce * script:WaitForChild("Configuration"):GetAttribute("CharDensityUp"), 0) --force that make you go up by pressing space
end
else
local force = hrp:FindFirstChildOfClass("VectorForce")
if force then
if hum.MoveDirection.Magnitude == 0 then
if isHeadIn then
force.Force = Vector3.new(0, defaultForce * script:WaitForChild("Configuration"):GetAttribute("CharDensity"), 0) --force that makes you go up by being idle
end
else
force.Force = Vector3.new(0, defaultForce, 0) --force that makes you stay still when floating in the surface
end
end
end
--Mobile tap detection
tapCon = game:GetService("UserInputService").TouchTapInWorld:Connect(function()
if not swimModule.Enabled or isHeadIn or not isLowerIn then return end
gOut()
end)
--Underwater lighting
if isCameraIn then
lightingModule:Add()
else
lightingModule:Remove()
end
end)
--Player died handler
local function died()
lightingModule:Remove()
con:Disconnect()
end
local humCon = hum.Died:Connect(died)
And here is a short clip of the infinite jump bug spam fixed:
robloxapp-20231025-0239138.wmv (2.4 MB)
Hello! I have one issue, how do you make the player use the swimmable part when they’re seated? It jumps out my seated player when they enter the water.
Honestly right now I don’t remember. I’ll have a look at the code and tell you when I have some spare time.
I’ll have a look at this when I have the time
Aren’t you supposed to update the container for CollectionService on CollectionService tag added?
local function folderChanged() --if you want to update the water parts this tracks the change
container = folder or game:GetService("CollectionService"):GetTagged(tag)
zone = zonePlus.new(container)
end
if script.PartFolder.Value then
container.ChildAdded:Connect(folderChanged)
container.ChildRemoved:Connect(folderChanged)
else
game:GetService("CollectionService"):GetInstanceAddedSignal(script.CollectionServiceTag.Value):Connect(folderChanged)
game:GetService("CollectionService"):GetInstanceRemovedSignal(script.CollectionServiceTag.Value):Connect(folderChanged)
end
folderChanged() works both for the folder and collectionService
I added this:
container = folder or game:GetService("CollectionService"):GetTagged(tag)
Inside the FolderChanged() function.
Shouldn’t that line also be added in your local script?
If someone doesn’t mind can they help me with this problem: How can I use parallel lua scripting to improve performance of terrain generation
Oh, I thought it was written like that on my script. I’ll change it. Thanks
Is there a way to let it work with mesh water that is client-side (duplicated from replicated storage to workspace on client-side)?
I have tried using tags and other ways but nothing worked.
The whole system is client sided meaning it should technically work
But it doesnt no matter what i did, but after having a good sleep ill try again
Thanks for the resource and tutorial!
Unfortunately, something prevents my character model from swimming - up, down, left or right. The jump mechanism is the only feature that works.
Here is an image of my character. Despite its unconventional design, it is fully rigged and is compatible with Roblox.
Here is a video of the issue:
What would be the issue here? I’ve tried changing CharDensity and CharDensityUp, but the problem hasn’t been fixed.
(Ignore the first person setting - I’ve toggled it on and off, and there’s been no change to the issue)