Skip to content

Commit

Permalink
Merge pull request #26 from Galaco/refactor
Browse files Browse the repository at this point in the history
Support for Leafv0 format in pre-v20 bsps
  • Loading branch information
Galaco authored Mar 27, 2019
2 parents 85d08f3 + 8403202 commit 208dcd7
Show file tree
Hide file tree
Showing 15 changed files with 171 additions and 125 deletions.
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@
[![codecov](https://codecov.io/gh/Galaco/bsp/branch/master/graph/badge.svg)](https://codecov.io/gh/Galaco/bsp)

# Bsp
Go library for manipulating Source Engine .bsp map files.
Go library for handling Source Engine .bsp map files.

### Features:
* Read support for (most) non-xbox360 bsps.
* Freely modify and resize any Lump data.
* Limited write support
* Read support for (most) non-xbox360 bsps (v20,21). v19 support limited, may work
* Freely modify and resize any Lump data
* Limited write support, mostly untested

##### Not all lumps are current supported, but can be freely read and modified, as they are treated as `[]byte`

The following lumps currently have a full implementation for v20 bsp's (tested against CS:S & CS:GO):
The following lumps currently have a full implementation for v20 & v21 bsp's (tested against CS:S & CS:GO):

```
0: Entdata
Expand Down Expand Up @@ -83,6 +83,7 @@ package main

import (
"github.com/galaco/bsp"
"github.com/galaco/bsp/lumps"
"log"
"os"
)
Expand All @@ -100,15 +101,15 @@ func main() {
}
f.Close()

lump := file.GetLump(bsp.LUMP_ENTITIES).(*lump.Entities)
lump := file.Lump(bsp.LumpEntities).(*lumps.Entities)
log.Println(lump.GetData())
}
```

## Real World examples
* Proof of concept BSP viewer: [https://github.com/Galaco/Lambda-Client](https://github.com/Galaco/Lambda-Client)
* Insert game_text newline placeholder characters (avoids Hammer crash) as a compile step: [https://github.com/Galaco/CS-GO-game_text-newline-inserter/tree/golang](https://github.com/Galaco/CS-GO-game_text-newline-inserter/tree/golang)
* Bspzip filelist generator from a mountable resource directory: [https://github.com/Galaco/bspzip-traverser](https://github.com/Galaco/bspzip-traverser)
* Proof of concept BSP viewer: [https://github.com/Galaco/Lambda-Client](https://github.com/Galaco/Lambda-Client)


# Contributing
Expand Down
14 changes: 7 additions & 7 deletions bsp.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,18 @@ type HeaderLump struct {
Id [4]byte
}

// GetHeader gets the header for a bsp.
func (bsp *Bsp) GetHeader() Header {
// Header gets the header for a bsp.
func (bsp *Bsp) Header() Header {
return bsp.header
}

// GetLump gets the lump for a given id.
func (bsp *Bsp) GetLump(index LumpId) lumps.ILump {
return bsp.GetLumpRaw(index).GetContents()
// Lump gets the lump for a given id.
func (bsp *Bsp) Lump(index LumpId) lumps.ILump {
return bsp.RawLump(index).Contents()
}

// GetLumpRaw gets the lump for a given id.
func (bsp *Bsp) GetLumpRaw(index LumpId) *Lump {
// RawLump gets the lump for a given id.
func (bsp *Bsp) RawLump(index LumpId) *Lump {
return &bsp.lumps[int(index)]
}

Expand Down
10 changes: 5 additions & 5 deletions bsp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,17 @@ func TestLumpExports(t *testing.T) {
// Verify lump lengths
lumpIndex := 0
for lumpIndex < 64 {
lump := file.GetLump(LumpId(lumpIndex))
rawLump := file.GetLumpRaw(LumpId(lumpIndex))
lump := file.Lump(LumpId(lumpIndex))
rawLump := file.RawLump(LumpId(lumpIndex))
lumpBytes, err := lump.Marshall()
if err != nil {
t.Error(err)
}
if len(lumpBytes) != int(file.GetHeader().Lumps[lumpIndex].Length) {
if len(lumpBytes) != int(file.Header().Lumps[lumpIndex].Length) {
t.Errorf("Lump: %d length mismatch. Got: %dbytes, expected: %dbytes", lumpIndex, len(lumpBytes), file.header.Lumps[lumpIndex].Length)
} else {
log.Printf("Index: %d, Expected: %d, Actual: %d\n", lumpIndex, len(rawLump.GetRawContents()), len(lumpBytes))
if !bytes.Equal(lumpBytes, rawLump.GetRawContents()) {
log.Printf("Index: %d, Expected: %d, Actual: %d\n", lumpIndex, len(rawLump.RawContents()), len(lumpBytes))
if !bytes.Equal(lumpBytes, rawLump.RawContents()) {
t.Errorf("Lump: %d data mismatch", lumpIndex)
}
}
Expand Down
128 changes: 64 additions & 64 deletions internal/versions/v20.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,133 +11,133 @@ func Getv20Lump(index int) (lumps.ILump, error) {
var err error
switch index {
case 0:
ret = &lumps.EntData{}
ret = new(lumps.EntData)
case 1:
ret = &lumps.Planes{}
ret = new(lumps.Planes)
case 2:
ret = &lumps.TexData{}
ret = new(lumps.TexData)
case 3:
ret = &lumps.Vertex{}
ret = new(lumps.Vertex)
case 4:
ret = &lumps.Visibility{}
ret = new(lumps.Visibility)
case 5:
ret = &lumps.Node{}
ret = new(lumps.Node)
case 6:
ret = &lumps.TexInfo{}
ret = new(lumps.TexInfo)
case 7:
ret = &lumps.Face{}
ret = new(lumps.Face)
case 8:
ret = &lumps.Lighting{}
ret = new(lumps.Lighting)
case 9:
ret = &lumps.Occlusion{}
ret = new(lumps.Occlusion)
case 10:
ret = &lumps.Leaf{}
ret = new(lumps.Leaf)
case 11:
ret = &lumps.FaceId{}
ret = new(lumps.FaceId)
case 12:
ret = &lumps.Edge{}
ret = new(lumps.Edge)
case 13:
ret = &lumps.Surfedge{}
ret = new(lumps.Surfedge)
case 14:
ret = &lumps.Model{}
ret = new(lumps.Model)
case 15:
ret = &lumps.WorldLight{}
ret = new(lumps.WorldLight)
case 16:
ret = &lumps.LeafFace{}
ret = new(lumps.LeafFace)
case 17:
ret = &lumps.LeafBrush{}
ret = new(lumps.LeafBrush)
case 18:
ret = &lumps.Brush{}
ret = new(lumps.Brush)
case 19:
ret = &lumps.BrushSide{}
ret = new(lumps.BrushSide)
case 20:
ret = &lumps.Area{}
ret = new(lumps.Area)
case 21:
ret = &lumps.AreaPortal{}
ret = new(lumps.AreaPortal)
case 22:
ret = &lumps.Unimplemented{} //portals | unused0 | propcollision
ret = new(lumps.Unimplemented) //portals | unused0 | propcollision
case 23:
ret = &lumps.Unimplemented{} //clusters | unused1 | prophulls
ret = new(lumps.Unimplemented) //clusters | unused1 | prophulls
case 24:
ret = &lumps.Unimplemented{} //portalverts | unused2 | prophullverts
ret = new(lumps.Unimplemented) //portalverts | unused2 | prophullverts
case 25:
ret = &lumps.Unimplemented{} //clusterportals | unused3 | proptris
ret = new(lumps.Unimplemented) //clusterportals | unused3 | proptris
case 26:
ret = &lumps.DispInfo{}
ret = new(lumps.DispInfo)
case 27:
ret = &lumps.Face{}
ret = new(lumps.Face)
case 28:
ret = &lumps.PhysDisp{}
ret = new(lumps.PhysDisp)
case 29:
ret = &lumps.Unimplemented{} //physcollide - IN PROGRESS
ret = new(lumps.Unimplemented) //physcollide - IN PROGRESS
case 30:
ret = &lumps.VertNormal{}
ret = new(lumps.VertNormal)
case 31:
ret = &lumps.VertNormalIndice{}
ret = new(lumps.VertNormalIndice)
case 32:
ret = &lumps.Unimplemented{} //disp lightmap alphas - IS STRIPPED ANYWAY?
ret = new(lumps.Unimplemented) //disp lightmap alphas - IS STRIPPED ANYWAY?
case 33:
ret = &lumps.DispVert{}
ret = new(lumps.DispVert)
case 34:
ret = &lumps.DispLightmapSamplePosition{}
ret = new(lumps.DispLightmapSamplePosition)
case 35:
ret = &lumps.Game{}
ret = new(lumps.Game)
case 36:
ret = &lumps.LeafWaterData{}
ret = new(lumps.LeafWaterData)
case 37:
ret = &lumps.Unimplemented{} //primitives FIXME - Appears to be 4bytes unaccounted for at end of lump?
ret = new(lumps.Unimplemented) //primitives FIXME - Appears to be 4bytes unaccounted for at end of lump?
case 38:
ret = &lumps.PrimVert{}
ret = new(lumps.PrimVert)
case 39:
ret = &lumps.PrimIndice{}
ret = new(lumps.PrimIndice)
case 40:
ret = &lumps.Pakfile{} //pakfile
ret = new(lumps.Pakfile) //pakfile
case 41:
ret = &lumps.ClipPortalVerts{}
ret = new(lumps.ClipPortalVerts)
case 42:
ret = &lumps.Cubemap{}
ret = new(lumps.Cubemap)
case 43:
ret = &lumps.TexDataStringData{}
ret = new(lumps.TexDataStringData)
case 44:
ret = &lumps.TexDataStringTable{}
ret = new(lumps.TexDataStringTable)
case 45:
ret = &lumps.Overlay{}
ret = new(lumps.Overlay)
case 46:
ret = &lumps.LeafMinDistToWater{}
ret = new(lumps.LeafMinDistToWater)
case 47:
ret = &lumps.FaceMacroTextureInfo{}
ret = new(lumps.FaceMacroTextureInfo)
case 48:
ret = &lumps.DispTris{}
ret = new(lumps.DispTris)
case 49:
ret = &lumps.Unimplemented{} //physcollidesurface | prop blob
ret = new(lumps.Unimplemented) //physcollidesurface | prop blob
case 50:
ret = &lumps.Unimplemented{} //wateroverlays
ret = new(lumps.Unimplemented) //wateroverlays
case 51:
ret = &lumps.LeafAmbientIndexHDR{}
ret = new(lumps.LeafAmbientIndexHDR)
case 52:
ret = &lumps.LeafAmbientIndex{}
ret = new(lumps.LeafAmbientIndex)
case 53:
ret = &lumps.Unimplemented{} //lighting hdr
ret = new(lumps.Unimplemented) //lighting hdr
case 54:
ret = &lumps.WorldLightHDR{} //worldlights hdr
ret = new(lumps.WorldLightHDR) //worldlights hdr
case 55:
ret = &lumps.LeafAmbientLightingHDR{}
ret = new(lumps.LeafAmbientLightingHDR)
case 56:
ret = &lumps.LeafAmbientLighting{} //leaf ambient lighting
ret = new(lumps.LeafAmbientLighting) //leaf ambient lighting
case 57:
ret = &lumps.Unimplemented{} //xzippakfile
ret = new(lumps.Unimplemented) //xzippakfile
case 58:
ret = &lumps.FaceHDR{}
ret = new(lumps.FaceHDR)
case 59:
ret = &lumps.MapFlags{}
ret = new(lumps.MapFlags)
case 60:
ret = &lumps.OverlayFade{}
ret = new(lumps.OverlayFade)
case 61:
ret = &lumps.Unimplemented{} //overlay system levels
ret = new(lumps.Unimplemented) //overlay system levels
case 62:
ret = &lumps.Unimplemented{} //physlevel
ret = new(lumps.Unimplemented) //physlevel
case 63:
ret = &lumps.Unimplemented{} //disp multiblend
ret = new(lumps.Unimplemented) //disp multiblend
default:
err = errors.New("invalid lump id")
}
Expand Down
2 changes: 1 addition & 1 deletion internal/versions/versions.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ func GetLumpForVersion(bspVersion int, lumpId int) (lumps.ILump, error) {
case 21:
return Getv21Lump(lumpId)
default:
return &lumps.Unimplemented{}, nil
return new(lumps.Unimplemented), nil
}
}
25 changes: 16 additions & 9 deletions lump.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ type Lump struct {
loaded bool
}

// SetId Get lump identifier
// SetId sets lump identifier
// Id is the lump type id (not the id for the order the lumps are stored)
func (l *Lump) SetId(index LumpId) {
l.id = index
}

// GetContents Get the contents of a lump.
// Contents Get the contents of a lump.
// NOTE: Will need to be cast to the relevant lumps
func (l *Lump) GetContents() lumps.ILump {
func (l *Lump) Contents() lumps.ILump {
if !l.loaded {
if l.data.Unmarshall(l.raw) != nil {
return nil
Expand All @@ -41,9 +41,9 @@ func (l *Lump) SetContents(data lumps.ILump) {
l.loaded = false
}

// GetRawContents Get the raw []byte contents of a lump.
// N.B. This is the raw imported value. To get the raw value of a modified lump, use GetContents().Marshall()
func (l *Lump) GetRawContents() []byte {
// RawContents Get the raw []byte contents of a lump.
// N.B. This is the raw imported value. To get the raw value of a modified lump, use Contents().Marshall()
func (l *Lump) RawContents() []byte {
return l.raw
}

Expand All @@ -52,8 +52,8 @@ func (l *Lump) SetRawContents(raw []byte) {
l.raw = raw
}

// GetLength Get length of a lump in bytes.
func (l *Lump) GetLength() int32 {
// Length Get length of a lump in bytes.
func (l *Lump) Length() int32 {
return l.length
}

Expand All @@ -63,5 +63,12 @@ func getReferenceLumpByIndex(index int, version int32) (lumps.ILump, error) {
return nil, fmt.Errorf("invalid lump id: %d provided", index)
}

return versions.GetLumpForVersion(int(version), index)
l, err := versions.GetLumpForVersion(int(version), index)
if err != nil {
return nil, err
}

l.SetVersion(version)

return l, nil
}
10 changes: 5 additions & 5 deletions lump_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,19 @@ func TestGetReferenceLumpByIndex(t *testing.T) {
}
}

func TestLump_GetContents(t *testing.T) {
func TestLump_Contents(t *testing.T) {

}

func TestLump_GetLength(t *testing.T) {
func TestLump_Length(t *testing.T) {
sut := Lump{}
sut.length = 32
if sut.GetLength() != 32 {
if sut.Length() != 32 {
t.Error("incorrect length returned for lump")
}
}

func TestLump_GetRawContents(t *testing.T) {
func TestLump_RawContents(t *testing.T) {
t.Skip()
}

Expand All @@ -53,7 +53,7 @@ func TestLump_SetRawContents(t *testing.T) {
sut := Lump{}
data := []byte{0, 1, 4, 3, 2}
sut.SetRawContents(data)
for idx, b := range sut.GetRawContents() {
for idx, b := range sut.RawContents() {
if data[idx] != b {
t.Error("raw lump data mismatch")
}
Expand Down
2 changes: 2 additions & 0 deletions lumps/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ type ILump interface {

// Marshall Exports lump structure back to []byte.
Marshall() ([]byte, error)

SetVersion(version int32)
}
Loading

0 comments on commit 208dcd7

Please sign in to comment.