Modding Help Lua Error and Pet Despawning (UNSTABLE/NIGHTLY)

Discussion in 'Starbound Modding' started by Campaigner, Mar 16, 2015.

  1. Campaigner

    Campaigner Giant Laser Beams

    EDIT 3-18-2015 SOLVED
    A little update due to the new nightly build, with good news.

    The new nightly did not have any changes to the broken lua file. On a different stroke, I figured out how to work with anchors, so now I don't need the extra groundpet.lua. Now, my pets use the same files as the ship pets, but the exact same problem persists. I edited only one pet right now for testing, and it does spawn; it just dies almost immediately after.

    Using the Bunny Pet (Avian starter pet) as a base.
    The petbunny.monstertype has "anchorName" : "aviantechstation", making the anchor as the Avian's tech station.
    The aviantechstation.object has the following code;
    Code:
      "scripts" : [ "/objects/spawner/shipPetSpawner.lua" ],
      "scriptDelta" : 20,
      "shipPetType" : "petbunny",
      "spawnOffset" : [12, -1]
    This code is copied over to my spawner, replacing the previous script that activated on clicking.
    The custom spawner item acts as an anchor with the custom pet as the shipPetType instead of petbunny.
    The custom pet references the custom spawner as the anchorName.

    Essentially, my pet is now a copy of the pet bunny, just with a different anchorName and shipPetType. This managed to work! I'm not sure why the lua kept trying to reference what wasn't there, but I don't code nor know how, so that wasn't an error on my part (for once!).

    I'll cut to the chase. This is exactly what happens;

    1. Place a pet spawner down (from my mod, Assorted Crafting Things)
    2. Summon the pet.
    3. Pet despawns after a few seconds.

    On March 8th, I unpacked the files, and touched up my mod by copying the groundpet.lua, and removing all mentions of "anchor", much like I did for the mod currently on the site. It worked all fine and dandy, and then a new patch comes out for Nightly. I do the same thing, editing the files, and upon testing it out, knowing something may be off, my pet did what was posted above. So like the smart modder should, I go to my log file. Here's what was wrong;

    Code:
    [18:57:32.794] Error: Exception while invoking lua function 'update'. (LuaException) Error code 2, [string "/monsters/pets/campworks_groundpet.lua"]:270: attempt to call global 'findGroundPosition' (a nil value)
      0000000038006BD0
      000000000657D700 
    The file "campworks_groundpet.lua" is just the copy of "groundpet.lua", but renamed so that it doesn't clash with the one working with normal pets. The only mention of "findGroundPosition" is in the campworks_groundpet.lua, as is "groundPosition". The Lua is as follows:


    Code:
    function init()
      self.pathing = {}
      self.pathing.stuckTimer = 0
      self.pathing.maxStuckTime = 2
    
      self.jumpCooldown = 0
      self.jumpMaxCooldown = 1
    
      self.movementParameters = mcontroller.baseParameters()
      self.jumpHoldTime = self.movementParameters.airJumpProfile.jumpHoldTime
      self.jumpSpeed = self.movementParameters.airJumpProfile.jumpSpeed
      self.runSpeed = self.movementParameters.runSpeed
    
      self.stuckPosition = mcontroller.position()
      self.stuckCount = 0
    
      self.scriptDelta = 5
    
      storage.petResources = storage.petResources or entity.configParameter("petResources")
      self.petResourceDeltas = entity.configParameter("petResourceDeltas")
      setPetResources(storage.petResources)
    
      local states = stateMachine.scanScripts(entity.configParameter("scripts"), "(%a+State)%.lua")
      self.state = stateMachine.create(states)
    
      local actionStates = {}
      local actions = stateMachine.scanScripts(entity.configParameter("scripts"), "(%a+Action)%.lua")
      for _, action in pairs(actions) do
        table.insert(actionStates, 1, action)
      end
      self.actionState = stateMachine.create(actionStates)
      self.autoPickState = false
    
      self.actionState.leavingState = function(stateName)
        self.querySurroundingsTimer = 0
      end
    
      self.followTarget = 0
    
      self.behaviorName = entity.configParameter("behavior")
      self.behavior = _ENV[self.behaviorName]
    
      storage.knownPlayers = storage.knownPlayers or entity.configParameter("knownPlayers", {})
      storage.foodLikings = storage.foodLikings or entity.configParameter("foodLikings", {})
    
      self.querySurroundingsCooldown = entity.configParameter("querySurroundingsCooldown", 3)
      self.querySurroundingsTimer = 1
      self.querySurroundingsRange = entity.configParameter("querySurroundingsRange", 50)
    
      self.standTimer = 0
    
      self.debug = true
    
      if capturepod and capturepod.onInit then
        capturepod.onInit()
      end
      if self.behavior and self.behavior.init then
        self.behavior.init()
      end
    end
    
    function update(dt)
      self.actionState.update(dt)
    
      if self.actionState.stateDesc() == "" and not self.state.update(dt) then
        self.state.pickState()
      end
    
      if self.querySurroundingsTimer <= 0 then
        querySurroundings()
        self.querySurroundingsTimer = self.querySurroundingsTimer + self.querySurroundingsCooldown
      end
    
      tickResources(dt)
      decrementTimers(dt)
    
      if not self.moved then script.setUpdateDelta(self.scriptDelta) end
    
      if self.debug then
        script.setUpdateDelta(1)
    
        if self.actionState.stateDesc() ~= "" then
          world.debugText(self.actionState.stateDesc(), mcontroller.position(), "blue")
        else
          world.debugText(self.state.stateDesc(), mcontroller.position(), "blue")
        end
        drawDebugResources()
      end
    end
    
    function damage(args)
      if capturepod ~= nil and capturepod.onDamage(args) then
        return
      end
    end
    
    function die()
      if capturepod ~= nil then
        capturepod.onDie()
      end
    end
    
    function querySurroundings()
      local nearEntities = world.entityQuery(mcontroller.position(), self.querySurroundingsRange, {
        includedTypes = { "player", "itemDrop", "monster", "object" },
        withoutEntityId = entity.id()
      })
    
      --Queue up reactions
      for _,entityId in ipairs(nearEntities) do
        self.behavior.reactTo(entityId)
      end
    
      --Run actions
      self.behavior.run()
    
      return false
    end
    
    function emote(emoteType)
      entity.burstParticleEmitter("emote"..emoteType)
    end
    
    function itemFoodLiking(entityName)
      if not entityName or root.itemType(entityName) ~= "consumable" then
        return false
      end
    
      local foodLiking = storage.foodLikings[entityName]
      if foodLiking == nil then
        return nil
      end
    
      --How much does it like the food
      if foodLiking == true or foodLiking == false then
        if foodLiking == true then
          foodLiking = math.random(50, 100)
        elseif foodLiking == false then
          foodLiking = math.random(0, 50)
        end
        storage.foodLikings[entityName] = foodLiking
      end
    
      return foodLiking
    end
    
    function petResources()
      local resources = {}
      for resourceName, resourceValue in pairs(storage.petResources) do
        resources[resourceName] = status.resource(resourceName)
      end
      return resources
    end
    
    function setPetResources(resources)
      for resourceName, resourceValue in pairs(resources) do
        status.setResource(resourceName, resourceValue)
      end
    end
    
    function tickResources(dt)
      for resourceName, resourceDelta in pairs(self.petResourceDeltas) do
        status.modifyResource(resourceName, resourceDelta * dt)
      end
    end
    
    function drawDebugResources()
      local resources = storage.petResources
      local position = mcontroller.position()
    
      local y = 2
      for resourceName, resourceValue in pairs(storage.petResources) do
        --Border
        world.debugLine(vec2.add(position, {-2, y+0.125}), vec2.add(position, {-2, y + 0.75}), "black")
        world.debugLine(vec2.add(position, {-2, y + 0.75}), vec2.add(position, {2, y + 0.75}), "black")
        world.debugLine(vec2.add(position, {2, y + 0.75}), vec2.add(position, {2, y+0.125}), "black")
        world.debugLine(vec2.add(position, {2, y+0.125}), vec2.add(position, {-2, y+0.125}), "black")
    
        local width = 3.75 * status.resource(resourceName) / 100
        world.debugLine(vec2.add(position, {-1.875, y + 0.25}), vec2.add(position, {-1.875 + width, y + 0.25}), "green")
        world.debugLine(vec2.add(position, {-1.875, y + 0.375}), vec2.add(position, {-1.875 + width, y + 0.375}), "green")
        world.debugLine(vec2.add(position, {-1.875, y + 0.5}), vec2.add(position, {-1.875 + width, y + 0.5}), "green")
        world.debugLine(vec2.add(position, {-1.875, y + 0.625}), vec2.add(position, {-1.875 + width, y + 0.625}), "green")
    
        world.debugText(resourceName, vec2.add(position, {2.25, y - 0.125}), "blue")
        y = y + 1
      end
    end
    
    function decrementTimers(dt)
      self.querySurroundingsTimer = self.querySurroundingsTimer - dt
      self.jumpCooldown = self.jumpCooldown - dt
      self.standTimer = self.standTimer - dt
    end
    
    function setMovementState(running)
      if not mcontroller.onGround() then
        if mcontroller.liquidMovement() then
          entity.setAnimationState("movement", "swim")
        else
          setJumpState()
        end
      else
        if running then
          entity.setAnimationState("movement", "run")
        else
          entity.setAnimationState("movement", "walk")
        end
      end
    end
    
    function setIdleState()
      local currentState = entity.animationState("movement")
      if currentState ~= "idle" and currentState ~= "stand" then
        self.standTimer = entity.configParameter("idle.standTime", 2)
      end
    
      if not mcontroller.onGround() then
        setJumpState()
      elseif self.standTimer < 0 then
        entity.setAnimationState("movement", "idle")
      else
        entity.setAnimationState("movement", "stand")
      end
    end
    
    function setJumpState()
      if mcontroller.yVelocity() > 0 then
        entity.setAnimationState("movement", "jumping")
      else
        entity.setAnimationState("movement", "falling")
      end
    end
    
    function boundingBox(force)
      if self.boundingBox and not force then return self.boundingBox end
    
      local collisionPoly = mcontroller.collisionPoly()
      local bounds = {0, 0, 0, 0}
    
      for _,point in pairs(collisionPoly) do
        if point[1] < bounds[1] then bounds[1] = point[1] end
        if point[2] < bounds[2] then bounds[2] = point[2] end
        if point[1] > bounds[3] then bounds[3] = point[1] end
        if point[2] > bounds[4] then bounds[4] = point[2] end
      end
      self.boundingBox = bounds
    
      return bounds
    end
    
    --------------------------------------------------------------------------------
    -- draw lines to display the specified rect {x1, y1, x2, y2} in the specified color, optionally offset by basePos
    function debugRect(rect, color, basePos)
      if basePos then rect = translate(rect, basePos) end
      world.debugLine({rect[1], rect[2]}, {rect[1], rect[4]}, color)
      world.debugLine({rect[1], rect[2]}, {rect[3], rect[2]}, color)
      world.debugLine({rect[3], rect[4]}, {rect[1], rect[4]}, color)
      world.debugLine({rect[3], rect[4]}, {rect[3], rect[2]}, color)
    end
    
    --------------------------------------------------------------------------------
    --MOVEMENT---------------------------------------------------------------------
    --------------------------------------------------------------------------------
    
    function approachPoint(dt, targetPosition, stopDistance, running)
      local toTarget = world.distance(targetPosition, mcontroller.position())
      local targetDistance = world.magnitude(targetPosition, mcontroller.position())
      local groundPosition = findGroundPosition(targetPosition, -20, 1, util.toDirection(-toTarget[1]))
    
      if groundPosition then
        self.approachPosition = groundPosition
      end
    
      if self.approachPosition and targetDistance > stopDistance then
        if moveTo(self.approachPosition, dt, {run = running}) then
          mcontroller.controlFace(self.pathing.deltaX or toTarget[1])
          setMovementState(running)
        else
          entity.setAnimationState("movement", "idle")
        end
    
        return false
      elseif targetDistance <= stopDistance then
        return true
      end
    end
    
    --------------------------------------------------------------------------------
    function move(direction, options)
      if options == nil then options = {} end
      if options.run == nil then options.run = false end
      direction = util.toDirection(direction)
    
      local position = mcontroller.position()
      local boundsEdge = 0
      local bounds = boundingBox()
      local tilePosition
      if direction > 0 then
        tilePosition = {math.ceil(position[1]), position[2]}
        boundsEdge = bounds[3]
      else
        tilePosition = {math.floor(position[1]), position[2]}
        boundsEdge = bounds[1]
      end
    
      --Stop at walls
      if world.lineTileCollision({position[1], position[2] + bounds[2] + 1.5}, { position[1] + boundsEdge + direction, position[2] + bounds[2] + 1.5}, true) then
        return false, "wall"
      end
    
      --Check if the position ahead is valid, including slopes
      local yDirs = {0, 1, -1}
      for _,yDir in ipairs(yDirs) do
        if validStandingPosition({tilePosition[1] + direction, tilePosition[2] + yDir}) then
          moveX(direction, options.run)
          return true
        end
      end
    
      return false, "ledge"
    end


    I'm unsure of why it's telling me this. The variable is there, but it's not finding it?
     
    Last edited: Mar 19, 2015
  2. AstralGhost

    AstralGhost Pangalactic Porcupine

    The error is telling you that the "findGroundPosition()" function is undefined.
    I can't tell you why, it's probably something to do with the nature of nightly builds. So you may want to compare this script with an older one that you know works. See why this function may not be defined.
     
  3. GROVER CURES HOUSES

    GROVER CURES HOUSES Void-Bound Voyager

    It appears to be undefined because it's not there. No such function is defined anywhere in starbound. It also wasn't defined over a month ago, so it's not exactly a nightly thing.

    Confused this with a completely different issue, please ignore. :(
     

Share This Page