Repository: markus-wa/demoinfocs-golang
Pull request #204 (2020-04-18 17:32:47)

fix various linting issues

codecov[bot]: # [Codecov](https://codecov.io/gh/markus-wa/demoinfocs-golang/pull/204?src=pr&el=h1) Report
> Merging [#204](https://codecov.io/gh/markus-wa/demoinfocs-golang/pull/204?src=pr&el=desc) into [v2](https://codecov.io/gh/markus-wa/demoinfocs-golang/commit/8e37a8d892275eece98a997b3636ec34eb32d23a&el=desc) will **not change** coverage.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/markus-wa/demoinfocs-golang/pull/204/graphs/tree.svg?width=650&height=150&src=pr&token=20emCaZRHz)](https://codecov.io/gh/markus-wa/demoinfocs-golang/pull/204?src=pr&el=tree)

```diff
@@           Coverage Diff           @@
##               v2     #204   +/-   ##
=======================================
  Coverage   89.63%   89.63%           
=======================================
  Files          29       29           
  Lines        2760     2760           
=======================================
  Hits         2474     2474           
  Misses        227      227           
  Partials       59       59           
```


| [Impacted Files](https://codecov.io/gh/markus-wa/demoinfocs-golang/pull/204?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pkg/demoinfocs/common/equipment.go](https://codecov.io/gh/markus-wa/demoinfocs-golang/pull/204/diff?src=pr&el=tree#diff-cGtnL2RlbW9pbmZvY3MvY29tbW9uL2VxdWlwbWVudC5nbw==) | `93.45% <ø> (ø)` | |
| [pkg/demoinfocs/sendtables/propdecoder.go](https://codecov.io/gh/markus-wa/demoinfocs-golang/pull/204/diff?src=pr&el=tree#diff-cGtnL2RlbW9pbmZvY3Mvc2VuZHRhYmxlcy9wcm9wZGVjb2Rlci5nbw==) | `75.00% <ø> (ø)` | |
| [pkg/demoinfocs/common/inferno.go](https://codecov.io/gh/markus-wa/demoinfocs-golang/pull/204/diff?src=pr&el=tree#diff-cGtnL2RlbW9pbmZvY3MvY29tbW9uL2luZmVybm8uZ28=) | `90.66% <100.00%> (ø)` | |
| [pkg/demoinfocs/common/player.go](https://codecov.io/gh/markus-wa/demoinfocs-golang/pull/204/diff?src=pr&el=tree#diff-cGtnL2RlbW9pbmZvY3MvY29tbW9uL3BsYXllci5nbw==) | `68.80% <100.00%> (ø)` | |
| [pkg/demoinfocs/datatables.go](https://codecov.io/gh/markus-wa/demoinfocs-golang/pull/204/diff?src=pr&el=tree#diff-cGtnL2RlbW9pbmZvY3MvZGF0YXRhYmxlcy5nbw==) | `98.25% <100.00%> (ø)` | |
| [pkg/demoinfocs/game\_events.go](https://codecov.io/gh/markus-wa/demoinfocs-golang/pull/204/diff?src=pr&el=tree#diff-cGtnL2RlbW9pbmZvY3MvZ2FtZV9ldmVudHMuZ28=) | `94.68% <100.00%> (ø)` | |
| [pkg/demoinfocs/game\_state.go](https://codecov.io/gh/markus-wa/demoinfocs-golang/pull/204/diff?src=pr&el=tree#diff-cGtnL2RlbW9pbmZvY3MvZ2FtZV9zdGF0ZS5nbw==) | `88.23% <100.00%> (ø)` | |
| [pkg/demoinfocs/net\_messages.go](https://codecov.io/gh/markus-wa/demoinfocs-golang/pull/204/diff?src=pr&el=tree#diff-cGtnL2RlbW9pbmZvY3MvbmV0X21lc3NhZ2VzLmdv) | `93.93% <100.00%> (ø)` | |
| [pkg/demoinfocs/parser.go](https://codecov.io/gh/markus-wa/demoinfocs-golang/pull/204/diff?src=pr&el=tree#diff-cGtnL2RlbW9pbmZvY3MvcGFyc2VyLmdv) | `87.62% <100.00%> (ø)` | |
| [pkg/demoinfocs/parsing.go](https://codecov.io/gh/markus-wa/demoinfocs-golang/pull/204/diff?src=pr&el=tree#diff-cGtnL2RlbW9pbmZvY3MvcGFyc2luZy5nbw==) | `88.75% <100.00%> (ø)` | |
| ... and [3 more](https://codecov.io/gh/markus-wa/demoinfocs-golang/pull/204/diff?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/markus-wa/demoinfocs-golang/pull/204?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/markus-wa/demoinfocs-golang/pull/204?src=pr&el=footer). Last update [8e37a8d...efb4b3d](https://codecov.io/gh/markus-wa/demoinfocs-golang/pull/204?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/.golangci.yml b/.golangci.yml
index 15f8540..f58b57e 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -14,6 +14,14 @@ linters:
     - gochecknoglobals
     - lll
     - typecheck
+    - gomnd
+issues:
+  exclude-rules:
+    # Exclude some linters from running on tests files.
+    - path: _test\.go
+      linters:
+        - wsl
+        - funlen
 linters-settings:
   gocritic:
     disabled-checks:
diff --git a/internal/constants/constants.go b/internal/constants/constants.go
new file mode 100644
index 0000000..bad41db
--- /dev/null
+++ b/internal/constants/constants.go
@@ -0,0 +1,9 @@
+package constants
+
+const (
+	MaxEdictBits                 = 11
+	EntityHandleIndexMask        = (1 << MaxEdictBits) - 1
+	EntityHandleSerialNumberBits = 10
+	EntityHandleBits             = MaxEdictBits + EntityHandleSerialNumberBits
+	InvalidEntityHandle          = (1 << EntityHandleBits) - 1
+)
diff --git a/pkg/demoinfocs/common/equipment.go b/pkg/demoinfocs/common/equipment.go
index 39d8367..bc5dfa0 100644
--- a/pkg/demoinfocs/common/equipment.go
+++ b/pkg/demoinfocs/common/equipment.go
@@ -122,6 +122,7 @@ func init() {
 	initEqElementToName()
 }
 
+//nolint:funlen
 func initEqNameToWeapon() {
 	eqNameToWeapon = make(map[string]EquipmentType)
 
@@ -198,6 +199,7 @@ func initEqNameToWeapon() {
 	eqNameToWeapon["worldspawn"] = EqWorld
 }
 
+//nolint:funlen
 func initEqElementToName() {
 	eqElementToName = make(map[EquipmentType]string)
 	eqElementToName[EqAK47] = "AK-47"
@@ -333,7 +335,9 @@ func (e Equipment) ZoomLevel() ZoomLevel {
 		return 0
 	}
 
+	// if the property doesn't exist we return 0 by default
 	val, _ := e.Entity.PropertyValue("m_zoomLevel")
+
 	return ZoomLevel(val.IntVal)
 }
 
@@ -350,7 +354,9 @@ func (e Equipment) AmmoReserve() int {
 		return 0
 	}
 
+	// if the property doesn't exist we return 0 by default
 	val, _ := e.Entity.PropertyValue("m_iPrimaryReserveAmmoCount")
+
 	return val.IntVal
 }
 
diff --git a/pkg/demoinfocs/common/inferno.go b/pkg/demoinfocs/common/inferno.go
index 6cfa2ae..cc84554 100644
--- a/pkg/demoinfocs/common/inferno.go
+++ b/pkg/demoinfocs/common/inferno.go
@@ -49,9 +49,8 @@ func (inf Inferno) UniqueID() int64 {
 func (inf Inferno) Fires() Fires {
 	entity := inf.Entity
 	origin := entity.Position()
-
-	var fires []Fire
 	nFires := entity.PropertyValueMust("m_fireCount").IntVal
+	fires := make([]Fire, 0, nFires)
 
 	for i := 0; i < nFires; i++ {
 		iStr := fmt.Sprintf("%03d", i)
diff --git a/pkg/demoinfocs/common/player.go b/pkg/demoinfocs/common/player.go
index 3fde24f..284c255 100644
--- a/pkg/demoinfocs/common/player.go
+++ b/pkg/demoinfocs/common/player.go
@@ -6,17 +6,10 @@ import (
 
 	"github.com/golang/geo/r3"
 
+	constants "github.com/markus-wa/demoinfocs-golang/v2/internal/constants"
 	st "github.com/markus-wa/demoinfocs-golang/v2/pkg/demoinfocs/sendtables"
 )
 
-const (
-	maxEdictBits                 = 11
-	entityHandleIndexMask        = (1 << maxEdictBits) - 1
-	entityHandleSerialNumberBits = 10
-	entityHandleBits             = maxEdictBits + entityHandleSerialNumberBits
-	invalidEntityHandle          = (1 << entityHandleBits) - 1
-)
-
 // Player contains mostly game-relevant player information.
 type Player struct {
 	demoInfoProvider demoInfoProvider // provider for demo info such as tick-rate or current tick
@@ -76,7 +69,7 @@ func (p *Player) IsAirborne() bool {
 
 	groundEntityHandle := p.Entity.Property("m_hGroundEntity").Value().IntVal
 
-	return groundEntityHandle == invalidEntityHandle
+	return groundEntityHandle == constants.InvalidEntityHandle
 }
 
 // FlashDurationTime returns the duration of the blinding effect as time.Duration instead of float32 in seconds.
@@ -129,7 +122,7 @@ This isn't very conclusive but it looks like IsFlashed isn't super reliable curr
 
 // Used internally to set the active weapon, see ActiveWeapon()
 func (p *Player) activeWeaponID() int {
-	return getInt(p.Entity, "m_hActiveWeapon") & entityHandleIndexMask
+	return getInt(p.Entity, "m_hActiveWeapon") & constants.EntityHandleIndexMask
 }
 
 // ActiveWeapon returns the currently active / equipped weapon of the player.
diff --git a/pkg/demoinfocs/datatables.go b/pkg/demoinfocs/datatables.go
index 9108f58..b1bed7a 100644
--- a/pkg/demoinfocs/datatables.go
+++ b/pkg/demoinfocs/datatables.go
@@ -7,22 +7,12 @@ import (
 	"github.com/golang/geo/r3"
 	"github.com/markus-wa/go-unassert"
 
+	constants "github.com/markus-wa/demoinfocs-golang/v2/internal/constants"
 	common "github.com/markus-wa/demoinfocs-golang/v2/pkg/demoinfocs/common"
 	events "github.com/markus-wa/demoinfocs-golang/v2/pkg/demoinfocs/events"
 	st "github.com/markus-wa/demoinfocs-golang/v2/pkg/demoinfocs/sendtables"
 )
 
-const (
-	maxEdictBits                 = 11
-	entityHandleIndexMask        = (1 << maxEdictBits) - 1
-	entityHandleSerialNumberBits = 10
-	entityHandleBits             = maxEdictBits + entityHandleSerialNumberBits
-	invalidEntityHandle          = (1 << entityHandleBits) - 1
-	maxEntities                  = 1 << maxEdictBits
-	maxPlayers                   = 64
-	maxWeapons                   = 64
-)
-
 func (p *parser) mapEquipment() {
 	for _, sc := range p.stParser.ServerClasses() {
 		switch sc.Name() {
@@ -215,6 +205,7 @@ func (p *parser) getOrCreatePlayer(entityID int, rp *playerInfo) (isNew bool, pl
 	return isNew, player
 }
 
+//nolint:funlen
 func (p *parser) bindNewPlayer(playerEntity st.Entity) {
 	entityID := playerEntity.ID()
 	rp := p.rawPlayers[entityID-1]
@@ -289,6 +280,8 @@ func (p *parser) bindNewPlayer(playerEntity st.Entity) {
 	}
 }
 
+const maxWeapons = 64
+
 func (p *parser) bindPlayerWeapons(playerEntity st.Entity, pl *common.Player) {
 	// Some demos have an additional prefix for player weapons weapon
 	var wepPrefix string
@@ -303,8 +296,8 @@ func (p *parser) bindPlayerWeapons(playerEntity st.Entity, pl *common.Player) {
 	for i := range cache {
 		i2 := i // Copy for passing to handler
 		playerEntity.Property(wepPrefix + fmt.Sprintf("%03d", i)).OnUpdate(func(val st.PropertyValue) {
-			entityID := val.IntVal & entityHandleIndexMask
-			if entityID != entityHandleIndexMask {
+			entityID := val.IntVal & constants.EntityHandleIndexMask
+			if entityID != constants.EntityHandleIndexMask {
 				if cache[i2] != 0 {
 					// Player already has a weapon in this slot.
 					delete(pl.Inventory, cache[i2])
@@ -351,7 +344,7 @@ func (p *parser) bindWeapons() {
 			case "CBaseCSGrenade":
 				// @micvbang TODO: handle grenades dropped by dead player.
 				// Grenades that were dropped by a dead player (and can be picked up by other players).
-			}
+			} //nolint:wsl
 		}
 	}
 
@@ -368,7 +361,7 @@ func (p *parser) bindGrenadeProjectiles(entity st.Entity) {
 	p.gameState.grenadeProjectiles[entityID] = proj
 
 	var wep common.EquipmentType
-	entity.OnCreateFinished(func() {
+	entity.OnCreateFinished(func() { //nolint:wsl
 		// copy the weapon so it doesn't get overwritten by a new entity in parser.weapons
 		wepCopy := *(getPlayerWeapon(proj.Thrower, wep))
 		proj.WeaponInstance = &wepCopy
diff --git a/pkg/demoinfocs/debug_on.go b/pkg/demoinfocs/debug_on.go
index 90bdb28..0dbae16 100644
--- a/pkg/demoinfocs/debug_on.go
+++ b/pkg/demoinfocs/debug_on.go
@@ -38,6 +38,7 @@ func debugGameEvent(d *msg.CSVCMsg_GameEventListDescriptorT, ge *msg.CSVCMsg_Gam
 	if debugGameEvents == yes {
 		// Map only the relevant data for each type
 		data := make(map[string]interface{})
+
 		for k, v := range mapGameEventData(d, ge) {
 			switch v.Type {
 			case typeStr:
diff --git a/pkg/demoinfocs/fake/parser.go b/pkg/demoinfocs/fake/parser.go
index 6e2060f..0164958 100644
--- a/pkg/demoinfocs/fake/parser.go
+++ b/pkg/demoinfocs/fake/parser.go
@@ -211,14 +211,12 @@ func (p *Parser) ParseNextFrame() (b bool, err error) {
 }
 
 func max(numbers map[int][]interface{}) (maxNumber int) {
-	for maxNumber = range numbers {
-		break
-	}
 	for n := range numbers {
 		if n > maxNumber {
 			maxNumber = n
 		}
 	}
+
 	return
 }
 
diff --git a/pkg/demoinfocs/game_events.go b/pkg/demoinfocs/game_events.go
index ba71ea8..d34e85f 100644
--- a/pkg/demoinfocs/game_events.go
+++ b/pkg/demoinfocs/game_events.go
@@ -3,6 +3,7 @@ package demoinfocs
 import (
 	"errors"
 	"fmt"
+
 	"github.com/golang/geo/r3"
 	"github.com/markus-wa/go-unassert"
 
@@ -22,6 +23,7 @@ func (p *parser) handleGameEvent(ge *msg.CSVCMsg_GameEvent) {
 	if p.gameEventDescs == nil {
 		p.eventDispatcher.Dispatch(events.ParserWarn{Message: "received GameEvent but event descriptors are missing"})
 		unassert.Error("received GameEvent but event descriptors are missing")
+
 		return
 	}
 
@@ -71,6 +73,7 @@ func (geh gameEventHandler) playerByUserID32(userID int32) *common.Player {
 
 type gameEventHandlerFunc func(map[string]*msg.CSVCMsg_GameEventKeyT)
 
+//nolint:funlen
 func newGameEventHandler(parser *parser) gameEventHandler {
 	geh := gameEventHandler{parser: parser}
 
@@ -192,15 +195,15 @@ func (geh gameEventHandler) roundStart(data map[string]*msg.CSVCMsg_GameEventKey
 	})
 }
 
-func (geh gameEventHandler) csWinPanelMatch(data map[string]*msg.CSVCMsg_GameEventKeyT) {
+func (geh gameEventHandler) csWinPanelMatch(map[string]*msg.CSVCMsg_GameEventKeyT) {
 	geh.dispatch(events.AnnouncementWinPanelMatch{})
 }
 
-func (geh gameEventHandler) roundAnnounceFinal(data map[string]*msg.CSVCMsg_GameEventKeyT) {
+func (geh gameEventHandler) roundAnnounceFinal(map[string]*msg.CSVCMsg_GameEventKeyT) {
 	geh.dispatch(events.AnnouncementFinalRound{})
 }
 
-func (geh gameEventHandler) roundAnnounceLastRoundHalf(data map[string]*msg.CSVCMsg_GameEventKeyT) {
+func (geh gameEventHandler) roundAnnounceLastRoundHalf(map[string]*msg.CSVCMsg_GameEventKeyT) {
 	geh.dispatch(events.AnnouncementLastRoundHalf{})
 }
 
@@ -222,7 +225,7 @@ func (geh gameEventHandler) roundEnd(data map[string]*msg.CSVCMsg_GameEventKeyT)
 	})
 }
 
-func (geh gameEventHandler) roundOfficiallyEnded(data map[string]*msg.CSVCMsg_GameEventKeyT) {
+func (geh gameEventHandler) roundOfficiallyEnded(map[string]*msg.CSVCMsg_GameEventKeyT) {
 	// Issue #42
 	// Sometimes grenades & infernos aren't deleted / destroyed via entity-updates at the end of the round,
 	// so we need to do it here for those that weren't.
@@ -263,11 +266,11 @@ func (geh gameEventHandler) botTakeover(data map[string]*msg.CSVCMsg_GameEventKe
 	})
 }
 
-func (geh gameEventHandler) beginNewMatch(data map[string]*msg.CSVCMsg_GameEventKeyT) {
+func (geh gameEventHandler) beginNewMatch(map[string]*msg.CSVCMsg_GameEventKeyT) {
 	geh.dispatch(events.MatchStart{})
 }
 
-func (geh gameEventHandler) roundFreezeEnd(data map[string]*msg.CSVCMsg_GameEventKeyT) {
+func (geh gameEventHandler) roundFreezeEnd(map[string]*msg.CSVCMsg_GameEventKeyT) {
 	geh.dispatch(events.RoundFreezetimeEnd{})
 }
 
diff --git a/pkg/demoinfocs/game_state.go b/pkg/demoinfocs/game_state.go
index 63aafee..be517e1 100644
--- a/pkg/demoinfocs/game_state.go
+++ b/pkg/demoinfocs/game_state.go
@@ -1,6 +1,7 @@
 package demoinfocs
 
 import (
+	constants "github.com/markus-wa/demoinfocs-golang/v2/internal/constants"
 	common "github.com/markus-wa/demoinfocs-golang/v2/pkg/demoinfocs/common"
 	st "github.com/markus-wa/demoinfocs-golang/v2/pkg/demoinfocs/sendtables"
 )
@@ -180,6 +181,7 @@ type participants struct {
 // Includes spectators.
 func (ptcp participants) ByUserID() map[int]*common.Player {
 	res := make(map[int]*common.Player)
+
 	for k, v := range ptcp.playersByUserID {
 		// We need to check if the player entity hasn't been destroyed yet
 		// See https://github.com/markus-wa/demoinfocs-golang/issues/98
@@ -269,11 +271,11 @@ func (ptcp participants) TeamMembers(team common.Team) []*common.Player {
 //
 // Returns nil if not found or if handle == invalidEntityHandle (used when referencing no entity).
 func (ptcp participants) FindByHandle(handle int) *common.Player {
-	if handle == invalidEntityHandle {
+	if handle == constants.InvalidEntityHandle {
 		return nil
 	}
 
-	entityID := handle & entityHandleIndexMask
+	entityID := handle & constants.EntityHandleIndexMask
 	player := ptcp.playersByEntityID[entityID]
 
 	if player == nil {
diff --git a/pkg/demoinfocs/net_messages.go b/pkg/demoinfocs/net_messages.go
index 34cd58c..ebe5665 100644
--- a/pkg/demoinfocs/net_messages.go
+++ b/pkg/demoinfocs/net_messages.go
@@ -42,13 +42,14 @@ func (p *parser) handlePacketEntities(pe *msg.CSVCMsg_PacketEntities) {
 				existing.Destroy()
 			}
 			p.gameState.entities[currentEntity] = p.stParser.ReadEnterPVS(r, currentEntity)
-		} else {
+		} else { //nolint:gocritic
 			// Delta Update
 			if entity := p.gameState.entities[currentEntity]; entity != nil {
 				entity.ApplyUpdate(r)
 			}
 		}
 	}
+
 	r.Pool()
 }
 
diff --git a/pkg/demoinfocs/parser.go b/pkg/demoinfocs/parser.go
index 50bab72..ce4a516 100644
--- a/pkg/demoinfocs/parser.go
+++ b/pkg/demoinfocs/parser.go
@@ -233,11 +233,12 @@ func (p *parser) UnregisterNetMessageHandler(identifier dp.HandlerIdentifier) {
 	p.msgDispatcher.UnregisterHandler(identifier)
 }
 
-func (p *parser) error() (err error) {
+func (p *parser) error() error {
 	p.errLock.Lock()
-	err = p.err
+	err := p.err
 	p.errLock.Unlock()
-	return
+
+	return err
 }
 
 func (p *parser) setError(err error) {
diff --git a/pkg/demoinfocs/parsing.go b/pkg/demoinfocs/parsing.go
index 76d80ed..6fe4093 100644
--- a/pkg/demoinfocs/parsing.go
+++ b/pkg/demoinfocs/parsing.go
@@ -201,6 +201,7 @@ const (
 	dcStringTables   demoCommand = 9
 )
 
+//nolint:funlen
 func (p *parser) parseFrame() bool {
 	cmd := demoCommand(p.bitReader.ReadSingleByte())
 
@@ -209,7 +210,7 @@ func (p *parser) parseFrame() bool {
 
 	// Skip 'player slot'
 	const nSlotBits = 8
-	p.bitReader.Skip(nSlotBits)
+	p.bitReader.Skip(nSlotBits) //nolint:wsl
 
 	debugDemoCommand(cmd)
 
@@ -288,12 +289,13 @@ var defaultNetMessageCreators = map[int]NetMessageCreator{
 	int(msg.NET_Messages_net_SetConVar):         func() proto.Message { return new(msg.CNETMsg_SetConVar) },
 }
 
+//nolint:funlen
 func (p *parser) parsePacket() {
 	// Booooring
 	// 152 bytes CommandInfo, 4 bytes SeqNrIn, 4 bytes SeqNrOut
 	// See at the bottom of the file what the CommandInfo would contain if you are interested.
 	const nCommandInfoBits = (152 + 4 + 4) << 3
-	p.bitReader.Skip(nCommandInfoBits)
+	p.bitReader.Skip(nCommandInfoBits) //nolint:wsl
 
 	// Here we go
 	p.bitReader.BeginChunk(p.bitReader.ReadSignedInt(32) << 3)
@@ -363,6 +365,7 @@ func (p *parser) handleFrameParsed(*frameParsedTokenType) {
 	for _, eventHandler := range p.delayedEventHandlers {
 		eventHandler()
 	}
+
 	p.delayedEventHandlers = p.delayedEventHandlers[:0]
 
 	p.currentFrame++
diff --git a/pkg/demoinfocs/sendtables/propdecoder.go b/pkg/demoinfocs/sendtables/propdecoder.go
index 9652669..2729ef9 100644
--- a/pkg/demoinfocs/sendtables/propdecoder.go
+++ b/pkg/demoinfocs/sendtables/propdecoder.go
@@ -1,3 +1,4 @@
+//nolint:varcheck,deadcode
 package sendtables
 
 import (
@@ -121,6 +122,7 @@ func (propertyDecoder) decodeInt(prop *sendTableProperty, reader *bit.BitReader)
 		if prop.flags.hasFlagSet(propFlagUnsigned) {
 			return int(reader.ReadVarInt32())
 		}
+
 		return int(reader.ReadSignedVarInt32())
 	}
 
@@ -137,6 +139,7 @@ func (propertyDecoder) decodeFloat(prop *sendTableProperty, reader *bit.BitReade
 	}
 
 	dwInterp := reader.ReadInt(prop.numberOfBits)
+
 	return prop.lowValue + ((prop.highValue - prop.lowValue) * (float32(dwInterp) / float32((int(1)<<uint(prop.numberOfBits))-1)))
 }
 
@@ -325,6 +328,7 @@ func (propertyDecoder) decodeString(reader *bit.BitReader) string {
 	if length > dataTableMaxStringLength {
 		length = dataTableMaxStringLength
 	}
+
 	return reader.ReadCString(length)
 }
 
diff --git a/pkg/demoinfocs/sendtables/st_parser.go b/pkg/demoinfocs/sendtables/st_parser.go
index eca7a4d..06fd233 100644
--- a/pkg/demoinfocs/sendtables/st_parser.go
+++ b/pkg/demoinfocs/sendtables/st_parser.go
@@ -8,6 +8,7 @@ import (
 	proto "github.com/gogo/protobuf/proto"
 
 	bit "github.com/markus-wa/demoinfocs-golang/v2/internal/bitread"
+	constants "github.com/markus-wa/demoinfocs-golang/v2/internal/constants"
 	msg "github.com/markus-wa/demoinfocs-golang/v2/pkg/demoinfocs/msg"
 )
 
@@ -188,6 +189,7 @@ func (p *SendTableParser) flattenDataTable(serverClassIndex int) {
 
 func buildPropertyLookupTable(props []flattenedPropEntry) map[string]int {
 	lookupTable := make(map[string]int)
+
 	for i := range props {
 		propName := props[i].name
 		lookupTable[propName] = i
@@ -207,7 +209,7 @@ func sortProperyPrios(fProps []flattenedPropEntry) []int {
 	prios := make([]int, len(prioSet))
 
 	i := 0
-	for k := range prioSet {
+	for k := range prioSet { //nolint:wsl
 		prios[i] = k
 		i++
 	}
@@ -238,7 +240,7 @@ func (p *SendTableParser) gatherExcludesAndBaseClasses(st *sendTable, collectBas
 
 func (p *SendTableParser) gatherProps(st *sendTable, serverClassIndex int, prefix string) {
 	var tmpFlattenedProps []flattenedPropEntry
-	p.gatherPropsIterate(st, serverClassIndex, prefix, &tmpFlattenedProps)
+	p.gatherPropsIterate(st, serverClassIndex, prefix, &tmpFlattenedProps) //nolint:wsl
 	p.serverClasses[serverClassIndex].flattenedProps = append(p.serverClasses[serverClassIndex].flattenedProps, tmpFlattenedProps...)
 }
 
@@ -277,6 +279,7 @@ func (p *SendTableParser) isPropertyExcluded(tab *sendTable, prop *sendTableProp
 			return true
 		}
 	}
+
 	return false
 }
 
@@ -286,6 +289,7 @@ func (p *SendTableParser) getTableByName(name string) *sendTable {
 			return &p.sendTables[i]
 		}
 	}
+
 	return nil
 }
 
@@ -306,8 +310,7 @@ func (p *SendTableParser) SetInstanceBaseline(scID int, data []byte) {
 func (p *SendTableParser) ReadEnterPVS(r *bit.BitReader, entityID int) Entity {
 	scID := int(r.ReadInt(p.classBits()))
 
-	const nSerialNumberBits = 10
-	r.Skip(nSerialNumberBits) // Serial Number
+	r.Skip(constants.EntityHandleSerialNumberBits) // Serial Number
 
 	return p.serverClasses[scID].newEntity(r, entityID)
 }
@@ -322,7 +325,7 @@ func (p *SendTableParser) classBits() int {
 //
 // Intended for internal use only.
 func NewSendTableParser() *SendTableParser {
-	p := new(SendTableParser)
-	p.instanceBaselines = make(map[int][]byte)
-	return p
+	return &SendTableParser{
+		instanceBaselines: make(map[int][]byte),
+	}
 }
diff --git a/pkg/demoinfocs/stringtables.go b/pkg/demoinfocs/stringtables.go
index af5dd92..414b8ef 100644
--- a/pkg/demoinfocs/stringtables.go
+++ b/pkg/demoinfocs/stringtables.go
@@ -107,7 +107,7 @@ func (p *parser) parseSingleStringTable(name string) {
 	}
 }
 
-func (p *parser) handleUpdateStringTable(tab *msg.CSVCMsg_UpdateStringTable) {
+func (p *parser) handleUpdateStringTable(tab *msg.CSVCMsg_UpdateStringTable) { //nolint:wsl
 	// No need for recoverFromUnexpectedEOF here as we do that in processStringTable already
 
 	cTab := p.stringTables[tab.TableId]
@@ -125,7 +125,7 @@ func (p *parser) handleUpdateStringTable(tab *msg.CSVCMsg_UpdateStringTable) {
 	}
 }
 
-func (p *parser) handleCreateStringTable(tab *msg.CSVCMsg_CreateStringTable) {
+func (p *parser) handleCreateStringTable(tab *msg.CSVCMsg_CreateStringTable) { //nolint:wsl
 	// No need for recoverFromUnexpectedEOF here as we do that in processStringTable already
 
 	p.processStringTable(tab)
@@ -180,7 +180,7 @@ func (p *parser) processStringTable(tab *msg.CSVCMsg_CreateStringTable) {
 		}
 
 		var entry string
-		if br.ReadBit() {
+		if br.ReadBit() { //nolint:wsl
 			if br.ReadBit() {
 				idx := br.ReadInt(5)
 				bytes2cp := int(br.ReadInt(5))
@@ -200,7 +200,7 @@ func (p *parser) processStringTable(tab *msg.CSVCMsg_CreateStringTable) {
 		hist = append(hist, entry)
 
 		var userdata []byte
-		if br.ReadBit() {
+		if br.ReadBit() { //nolint:wsl
 			if tab.UserDataFixedSize {
 				// Should always be < 8 bits => use faster ReadBitsToByte() over ReadBits()
 				userdata = []byte{br.ReadBitsToByte(int(tab.UserDataSizeBits))}
@@ -223,6 +223,7 @@ func (p *parser) processStringTable(tab *msg.CSVCMsg_CreateStringTable) {
 			if err != nil {
 				panic("WTF VOLVO PLS")
 			}
+
 			p.stParser.SetInstanceBaseline(int(classID), userdata)
 
 		case stNameModelPreCache:
diff --git a/pkg/demoinfocs/user_messages.go b/pkg/demoinfocs/user_messages.go
index 7c94d5d..bce4b92 100644
--- a/pkg/demoinfocs/user_messages.go
+++ b/pkg/demoinfocs/user_messages.go
@@ -10,7 +10,10 @@ import (
 )
 
 func (p *parser) handleUserMessage(um *msg.CSVCMsg_UserMessage) {
-	p.userMessageHandler.handler(msg.ECstrike15UserMessages(um.MsgType))(um)
+	handler := p.userMessageHandler.handler(msg.ECstrike15UserMessages(um.MsgType))
+	if handler != nil {
+		handler(um)
+	}
 }
 
 type userMessageHandler struct {
@@ -22,7 +25,8 @@ func (umh userMessageHandler) handler(msgType msg.ECstrike15UserMessages) userMe
 	if handler, eventKnown := umh.msgTypeToHandler[msgType]; eventKnown {
 		return handler
 	}
-	return func(*msg.CSVCMsg_UserMessage) { /* NOP */ }
+
+	return nil
 }
 
 func (umh userMessageHandler) dispatch(event interface{}) {


Test patch:
diff --git a/pkg/demoinfocs/game_state_test.go b/pkg/demoinfocs/game_state_test.go
index 721a5c0..ae494c1 100644
--- a/pkg/demoinfocs/game_state_test.go
+++ b/pkg/demoinfocs/game_state_test.go
@@ -5,6 +5,7 @@ import (
 
 	"github.com/stretchr/testify/assert"
 
+	constants "github.com/markus-wa/demoinfocs-golang/v2/internal/constants"
 	common "github.com/markus-wa/demoinfocs-golang/v2/pkg/demoinfocs/common"
 	st "github.com/markus-wa/demoinfocs-golang/v2/pkg/demoinfocs/sendtables"
 	stfake "github.com/markus-wa/demoinfocs-golang/v2/pkg/demoinfocs/sendtables/fake"
@@ -146,7 +147,7 @@ func TestParticipants_FindByHandle(t *testing.T) {
 
 	ptcps := participants{
 		playersByEntityID: map[int]*common.Player{
-			3000 & entityHandleIndexMask: pl,
+			3000 & constants.EntityHandleIndexMask: pl,
 		},
 	}
 
@@ -160,11 +161,11 @@ func TestParticipants_FindByHandle_InvalidEntityHandle(t *testing.T) {
 	pl.Team = common.TeamTerrorists
 	ptcps := participants{
 		playersByEntityID: map[int]*common.Player{
-			invalidEntityHandle & entityHandleIndexMask: pl,
+			constants.InvalidEntityHandle & constants.EntityHandleIndexMask: pl,
 		},
 	}
 
-	found := ptcps.FindByHandle(invalidEntityHandle)
+	found := ptcps.FindByHandle(constants.InvalidEntityHandle)
 
 	assert.Nil(t, found)
 }