. . . Posted May 1, 2019 Share Posted May 1, 2019 (edited) Hello, I need some help optimizing some of my friend's code which I can't figure out how.. Basically I want to merge the "cave" and "wmwa_totem" range checks to reduce any potential lag it could cause on weaker pcs. Here's the code. Spoiler local WMWA_DIG = G.Action() WMWA_DIG.str = "Wmwa Dig" WMWA_DIG.id = "WMWA_DIG" WMWA_DIG.fn = function(act) local inst = act.target if inst.components.health:IsDead() or inst:HasTag("playerghost") or inst.components.rider:IsRiding() or inst.sg:HasStateTag("busy") or inst.components.locomotor:WantsToMoveForward() then return end if inst.dig_cd == true then inst.components.talker:Say(GetString(inst, "DIG_COOLDOWN")) return end --local x, y, z = inst.Transform:GetWorldPosition() --print("FIND", inst, radius, musttags and #musttags or 0, canttags and #canttags or 0, mustoneoftags and #mustoneoftags or 0) --local cave = G.TheSim:FindEntities(x, y, z, 500, 0, 0, {"cavee", "wmwa_totem"}) local cave = G.GetClosestInstWithTag({"cavee"}, inst, 250) local wmwa_totem = G.GetClosestInstWithTag({"wmwa_totem"}, inst, 750) -- Would like to merge the 250 range check with this one local function WmwaDiggy(inst) inst.dig_cd = true inst:DoTaskInTime(2, function() inst.dig_cd = nil end)--cooldown 1 minute inst.components.locomotor:Stop() inst.components.health:SetInvincible(true) ShakeAllCameras(CAMERASHAKE.VERTICAL,3, .3, .3, inst, .01) if inst.components.playercontroller ~= nil then inst.components.playercontroller:Enable(false) end inst.sg:GoToState("wmwa_dig") inst.components.talker:Say(GetString(inst, "DIG")) inst:DoTaskInTime(.5, function() inst:SetCameraDistance(8) end) inst:DoTaskInTime(1, function() inst:SetCameraDistance(5) end) inst:DoTaskInTime(2, function() inst:SetCameraDistance(2) end) if inst.blind == nil then inst:ScreenFade(false, 3.25) end end if wmwa_totem then WmwaDiggy(inst) inst:DoTaskInTime(2.75, function() if inst.blind == nil then inst:ScreenFade(true, 1) end inst:SetCameraDistance() local x, y, z = wmwa_totem.Transform:GetWorldPosition() inst.Transform:SetPosition(x+1.5, y, z) if inst.components.playercontroller ~= nil then inst.components.playercontroller:Enable(true) end inst.components.health:SetInvincible(false) end) return elseif cave and not wmwa_totem then WmwaDiggy(inst) inst:DoTaskInTime(2.75, function() if inst.blind == nil then inst:ScreenFade(true, 1) end inst:SetCameraDistance() local x, y, z = cave.Transform:GetWorldPosition() inst.Transform:SetPosition(x+1.5, y, z) if inst.components.playercontroller ~= nil then inst.components.playercontroller:Enable(true) end inst.components.health:SetInvincible(false) end) return else inst.components.talker:Say(GetString(inst, "DIG_NO_CAVE")) end end AddAction(WMWA_DIG) What my friend wants to do is when this action is preformed if there are no "wmwa_totem" in range then this action takes you to the nearest cave_entrance/cave_exit, but if there's a wmwa_totem in the 750 range then it prioritizes taking you to there instead of cave_entrance/cave_exit. The code right now works, but my friend really wants to merge the range checks then unnecessary lag isn't caused since the action already is performance heavy with a 750 range check.. I tried using "FindEntity" function from simutil, but that seems to only get 1 entity which is closest to you and doesn't find all entities within range allowing a specific one priority. I also tried using "TheSim:FindEntities" but it always causes crashes or just doesn't work and I can't figure out why .. Hopefully someone smarter than me can help out with this, thanks for your time have a good day/night ! Edited May 1, 2019 by Warbucks Link to comment Share on other sites More sharing options...
Ultroman Posted May 1, 2019 Share Posted May 1, 2019 (edited) Look at what GetClosestInstWithTag actually does. function GetClosestInstWithTag(tag, inst, radius) local x, y, z = inst.Transform:GetWorldPosition() local ents = TheSim:FindEntities(x, y, z, radius, type(tag) == "string" and { tag } or tag) return ents[1] ~= inst and ents[1] or ents[2] end It's just a FindEntities call with a tag as a string or a list of tags, and then if the first (closest) entity is not the given inst, return that, otherwise return the second (second closest). This is how FindEntities works -- Description of important function, which finds specific entities within a range: -- TheSim:FindEntities(x, y, z, radius, mustHaveTags, cantHaveTags, mustHaveOneOfTheseTags) -- We have limited it to entities with the "player" tag, that are also not ghosts or otherwise in limbo. -- Radius has been set to 10 local players = TheSim:FindEntities(x, y, z, 10, {"player"}, {"playerghost", "INLIMBO"}, nil) Just leave mustHaveTags and cantHaveTags set to nil, and put in {"cavee", "wmwa_totem"} as mustHaveOneOfTheseTags. local x, y, z = inst.Transform:GetWorldPosition() local cavesAndTotems = G.TheSim:FindEntities(x, y, z, 750, nil, nil, {"cavee", "wmwa_totem"}) Then you can run through the cavesAndTotems list and do your checks. The list will be ordered with the closest entity first. The problem is, you want to check two different distances depending on which entity it is. You should basically say "if I have found a cave, and that cave is within a distance of 250 of my x,y,z then choose the cave, and otherwise pick the first totem I saw". All the functions for distance checks use distance squared in order to avoid doing squareroot calls, so when checking the distance you need to do: (distance squared < range * range) Here's the rest of the code: local entity_to_go_to = nil local cave_within_range = nil local stopCaveSearch = false for i, entity_in_list in ipairs(cavesAndTotems) do if entity_in_list:HasTag("cavee") then if not stopCaveSearch then local distance_to_cave = entity_in_list:GetDistanceSqToPoint(x, y, z)) if (distance_to_cave < (250*250) then -- Found a cave within 250 range. cave_within_range = entity_in_list end stopCaveSearch = true end else -- The entity is a totem. entity_to_go_to = entity_in_list break end end -- If we didn't find a single totem, set entity_to_go_to to cave_within_range if entity_to_go_to == nil then entity_to_go_to = cave_within_range end -- Remember, at this point entity_to_go_to may still be nil, since we might not have found anything. We always stop searching for caves the second we see one, because we want the closest one and only if it is within range. If the first one we find is outside the range, then we don't want to waste time looking at more caves. If the first cave IS within range, then we don't care about any of the other caves. However, if we find a totem, we instantly break from the loop. If we do not find a totem at all, we apply the value of the cave_within_range variable to the entity_to_go_to variable. If we didn't find a cave, entity_to_go_to will still be nil, so we did not find any entity to teleport to. 750 is still a large range, but as long as it's not a check being done in a loop or all the time, you should be fine. Edited May 2, 2019 by Ultroman Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now