Jump to content

Errors getting killed and casting a spell in client graphics


Recoil

Recommended Posts

I am running into 2 different problems.  Right now I can attack an npc, but if I let it kill me then about 3/4 of the time I get the following null exception in Client Graphics on the following code.  The line the error is happening on is right under the ''' Xml comment:

{"Object reference not set to an instance of an object."}

    Public Sub DrawMapTile(ByVal locX As Long, ByVal locY As Long)
        Dim i As Long
        Dim srcrect As New Rectangle(0, 0, 0, 0)
        Dim tmpSprite As Sprite
        If GettingMap Then Exit Sub
        With Map.Tile(locX, locY)
            For i = MapLayer.Ground To MapLayer.Mask2
                ' skip tile if tileset isn't set
                '''
                If .Layer(i).Tileset > 0 Then
                    With srcrect
                        .X = Map.Tile(locX, locY).Layer(i).X * 32
                        .Y = Map.Tile(locX, locY).Layer(i).Y * 32
                        .Width = 32
                        .Height = 32
                    End With
                    tmpSprite = New Sprite(TileSetTexture(.Layer(i).Tileset))
                    tmpSprite.TextureRect = New IntRect(srcrect.X, srcrect.Y, srcrect.Width, srcrect.Height)
                    tmpSprite.Position = New Vector2f(ConvertMapX(locX * PIC_X), ConvertMapY(locY * PIC_Y))
                    GameWindow.Draw(tmpSprite)
                End If
            Next
        End With
    End Sub

Or the same error here:

        Public Sub DrawMapAni(ByVal locX As Long, ByVal locY As Long, ByVal LayerNum As Long)
        Dim srcrect As New Rectangle(0, 0, 0, 0)
        Dim tmpSprite As Sprite

        If GettingMap Or Not ShowAnimLayers Then Exit Sub
        With Map.Tile(locX, locY)
            ' skip tile if tileset isn't set
            '''
            If .Layer(LayerNum).Tileset > 0 Then
                With srcrect
                    .X = Map.Tile(locX, locY).Layer(LayerNum).X * 32
                    .Y = Map.Tile(locX, locY).Layer(LayerNum).Y * 32
                    .Width = 32
                    .Height = 32
                End With
                tmpSprite = New Sprite(TileSetTexture(.Layer(LayerNum).Tileset))
                tmpSprite.TextureRect = New IntRect(srcrect.X, srcrect.Y, srcrect.Width, srcrect.Height)
                tmpSprite.Position = New Vector2f(ConvertMapX(locX * PIC_X), ConvertMapY(locY * PIC_Y))
                GameWindow.Draw(tmpSprite)
            End If
        End With
    End Sub

My second issue is when I double click inside my spells panel to cast a spell on the npc.  99% of the time I will pull this in only 1 location in code, still in ClientGraphics:

{"Arithmetic operation resulted in an overflow."}

    Public Sub DrawBars()
        Dim tmpY As Long
        Dim tmpX As Long
        Dim barWidth As Long
        Dim rec(1) As Rectangle

        ' check for casting time bar
        If SpellBuffer > 0 Then
            ' lock to player
            tmpX = GetPlayerX(MyIndex) * PIC_X + Player(MyIndex).XOffset
            tmpY = GetPlayerY(MyIndex) * PIC_Y + Player(MyIndex).YOffset + 35
            ' calculate the width to fill
            '''
            barWidth = ((GetTickCount() - SpellBufferTimer) / ((GetTickCount() - SpellBufferTimer) + (Spell(PlayerSpells(SpellBuffer)).CastTime * 1000)) * 64)
            ' draw bars
            rec(1) = New Rectangle(ConvertMapX(tmpX), ConvertMapY(tmpY), barWidth, 4)
            Dim rectShape As New RectangleShape(New Vector2f(barWidth, 4))
            rectShape.Position = New Vector2f(ConvertMapX(tmpX), ConvertMapY(tmpY))
            rectShape.FillColor = SFML.Graphics.Color.Cyan
            GameWindow.Draw(rectShape)
        End If
    End Sub

Link to comment
Share on other sites

Your first issue could be caused by the loading of a map while trying to render the screen. (Or improper redefining of the map when loading occurs.)

Here is the chain of events that you are seeing:

  • You're fighting an NPC.
  • You die. Which warps you to spawn.
  • The game screen enters a render loop, starts to draw the map.
  • The client sees the warp packet and destroys the map to reload.
  • The drawing continues but freaks out when the layers no longer exist.

There are several different options on approaching a fix for this.  There are a lot of strategies to tackle cross threading issues like this. You could send the new map data to the main thread and parse it there between frames for example.

But here is a better way. The idea is that we don't want the map to be null while trying to render. We can accomplish this with SyncLocks.

Place a new global variable somewhere (Right around the definition for the map would suffice.) and define it as follows. -

Public MapLock as new Object()

Next, go to Sub ClearMap() and surround the Subs contents with

SyncLock(MapLock)
'Code Here
end SyncLock

Finally, head over to Sub GameLoop and add those two lines of code again.

Add SyncLock(MapLock) before If CanMoveNow

and Add End SyncLock after your Day/Night If then block.

Let me know if that fixes your first issue.

Link to comment
Share on other sites

I figured the second issue out.  If the spell has a cast time of 0 then it will boot.

If Spell(PlayerSpells(SpellBuffer)).CastTime > 0 Then
    barWidth = ((GetTickCount() - SpellBufferTimer) / ((GetTickCount() - SpellBufferTimer) + (Spell(PlayerSpells(SpellBuffer)).CastTime * 1000)) * 64)
End If

Link to comment
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...