Hello! I tried migrating my code into a multithreaded version using an actor, but for some reason im getting a bug. I have an “Animator” module, and both the local character and other entities use it, but for some reason the other entities throw an error saying it has to be a descendant of an actor to use task.synchronize… They’re both modules required by the same script, so I dont understand why this is happening? Any ideas?
This script initializes everything:
module that handles local character:
module that handles other entities:
Entities update like so:
function Entities.new(object)
local self = setmetatable({}, Entities)
self.object = object.Parent
self.humanoid = object.Parent:WaitForChild("Humanoid") :: Humanoid
self.trove = Trove.new()
self.isConnectedToDeconstructor = false
for _, child in self.object:GetDescendants() do
task.spawn(function()
self:handleChild(child)
end)
end
self.trove:Connect(self.object.DescendantAdded, function(...)
self:handleChild(...)
end)
self.trove:Connect(RunService.Heartbeat, function(...)
self:render(...)
end)
self.trove:Connect(object.Destroying, function()
self:destroy()
end)
self.trove:Connect(object:GetPropertyChangedSignal("Parent"), function()
if not object.Parent and not table.isfrozen(self) then
self:destroy()
end
end)
return self
end
function Entities:render(deltaTime)
local billboardGui = self.object:FindFirstChildWhichIsA("BillboardGui")
if not billboardGui then -- Not in render
return
end
local frame = billboardGui:FindFirstChild("Frame")
if not frame then
return
end
local humanoidRootPart = self.object:FindFirstChild("HumanoidRootPart")
if not humanoidRootPart then
return
end
local isMoving = if self.humanoid.MoveDirection == Vector3.zero then false else true
local Origin, Directon =
humanoidRootPart.Position,
CFrame.lookAt(humanoidRootPart.Position, humanoidRootPart.Position - Vector3.new(0, 1, 0)).LookVector.Unit * 4
local GroundRay = workspace:Raycast(Origin, Directon, groundRaycastParams)
local isOnGround = GroundRay and true or false
if not self.animator then
local expressions = ExternalEntityExpressionManager.new(frame)
if not expressions then
warn(`Failed to load for entity: {billboardGui.Name}`)
return
end
local animator = Animator.new(self.object, expressions, expressions.data.Category)
self.expressions = expressions
self.animator = animator
self.trove:Add(self.expressions, "destroy")
self.trove:Add(self.animator, "Destroy")
end
self.animator:Render(isMoving, isOnGround, deltaTime)
end
Local character updates like so:
trove:Connect(RunService.RenderStepped, function(deltaTime)
local isMoving = if humanoid.MoveDirection == Vector3.zero then false else true
local isSprinting = SprintMechanic:IsSprinting()
local characterYCord = humanoidRootPart.Position.Y
local cameraDistanceFromHead = (head.Position - CameraObject.CFrame.Position).Magnitude
if cameraDistanceFromHead < 1 then
billboardGui.Frame.Visible = false
else
billboardGui.Frame.Visible = true
end
if isMoving and isSprinting then
Camera:tweenFieldOfView(80, 0.3)
elseif not isMoving and isSprinting then
Camera:tweenFieldOfView(70, 0.7)
end
if Settings.alwaysRun then
self.sprint:Toggle(true, self:GetHumanoid()):andThen(function(isSprinting: boolean)
if isSprinting and self:IsMoving() then
Camera:tweenFieldOfView(80, 0.3)
end
end)
elseif not InputService:IsKeyDown(Enum.KeyCode.LeftShift) then
self.sprint:Toggle(false, self:GetHumanoid()):andThen(function(isSprinting: boolean)
if not isSprinting then
Camera:tweenFieldOfView(70, 1)
end
end)
end
if characterYCord <= -235 and not isTeleportingUp then
isTeleportingUp = true
humanoidRootPart.Anchored = true
humanoidRootPart.AssemblyLinearVelocity = Vector3.zero
UI.fadeScreen(true, 0.3)
task.spawn(function()
task.wait(0.3)
MapSystem:teleportToMap()
humanoidRootPart.Anchored = false
isTeleportingUp = false
UI.fadeScreen(false, 0.3)
end)
end
animator:Render(isMoving, self.isOnGround, deltaTime)
end)
Theres a lot of code so im not sure what to share specifically, if anyone has any ideas that would be greatly appreciated!