You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
hexmap/server/state/map.go

206 lines
5.9 KiB

package state
import (
"fmt"
"github.com/rs/xid"
"go.uber.org/zap/zapcore"
)
// HexOrientation is the enum for the direction hexes are facing.
type HexOrientation uint8
const (
// UnknownOrientation indicates that an invalid orientation was specified.
UnknownOrientation HexOrientation = 0
// PointyTop indicates hexes that have a pair of sides on either side in the horizontal direction,
// and points on the top and bottom in the vertical direction.
PointyTop HexOrientation = 1
// FlatTop indicates hexes that have a pair of points on either side in the horizontal direction,
// and sides on the top and bottom in the vertical direction.
FlatTop HexOrientation = 2
)
// String returns the equivalent JavaScript constant name.
func (o HexOrientation) String() string {
switch o {
case PointyTop:
return "POINTY_TOP"
case FlatTop:
return "FLAT_TOP"
default:
return fmt.Sprintf("[unknown HexOrientation %d]", o)
}
}
// LineParity indicates whether odd or even lines are indented.
type LineParity uint8
const (
// UnknownParity indicates that parity was not specified or unknown.
UnknownParity LineParity = 0
// OddLines indicates that odd lines - 1, 3, 5... - are indented by 1/2 cell.
OddLines LineParity = 1
// EvenLines indicates that even lines - 0, 2, 4... - are indented by 1/2 cell.
EvenLines LineParity = 2
)
// String returns the equivalent JavaScript constant name.
func (o LineParity) String() string {
switch o {
case OddLines:
return "ODD_LINES"
case EvenLines:
return "EVEN_LINES"
default:
return fmt.Sprintf("[unknown LineParity %d]", o)
}
}
// Layout combines HexOrientation and LineParity to represent a map's display mode.
type Layout struct {
Orientation HexOrientation `json:"orientation"`
IndentedLines LineParity `json:"indentedLines"`
}
func (l Layout) MarshalLogObject(encoder zapcore.ObjectEncoder) error {
encoder.AddString("orientation", l.Orientation.String())
encoder.AddString("indentedLines", l.IndentedLines.String())
return nil
}
// HexCell contains data for a single cell of the map.
type HexCell struct {
// Color contains the color of the cell, in hex notation.
Color Color `json:"color"`
}
func (h HexCell) MarshalLogObject(encoder zapcore.ObjectEncoder) error {
encoder.AddString("color", h.Color.String())
return nil
}
// HexLine is a line of cells which are adjacent by flat sides in a vertical or horizontal direction.
type HexLine []HexCell
func (l HexLine) MarshalLogArray(encoder zapcore.ArrayEncoder) error {
var finalErr error
for _, cell := range l {
err := encoder.AppendObject(cell)
if err != nil && finalErr == nil {
finalErr = err
}
}
return finalErr
}
// Copy creates a deep copy of this HexLine.
func (l HexLine) Copy() HexLine {
duplicate := make(HexLine, len(l))
for index, value := range l {
duplicate[index] = value
}
return duplicate
}
// HexLayer is a two-dimensional plane of cells which are arranged into lines.
type HexLayer []HexLine
func (l HexLayer) MarshalLogArray(encoder zapcore.ArrayEncoder) error {
var finalErr error
for _, line := range l {
err := encoder.AppendArray(line)
if err != nil && finalErr == nil {
finalErr = err
}
}
return finalErr
}
// GetCellAt returns a reference to the cell at the given coordinates.
// If the coordinates are out of bounds for this map, an error will be returned.
func (l HexLayer) GetCellAt(c StorageCoordinates) (*HexCell, error) {
if int(c.Line) >= len(l) {
return nil, fmt.Errorf("line %d out of bounds (%d)", c.Line, len(l))
}
line := l[c.Line]
if int(c.Cell) >= len(line) {
return nil, fmt.Errorf("cell %d out of bounds (%d)", c.Cell, len(line))
}
return &(line[c.Cell]), nil
}
// Copy creates a deep copy of this HexLayer.
func (l HexLayer) Copy() HexLayer {
duplicate := make(HexLayer, len(l))
for index, value := range l {
duplicate[index] = value.Copy()
}
return duplicate
}
// HexMap contains the data for a map instance.
type HexMap struct {
// XID is the unique id of the HexMap, used to encourage clients not to blindly interact with a different map.
XID xid.ID `json:"xid"`
// Lines is the rough number of rows (in PointyTop orientation) or columns (in FlatTop orientation) in the map.
// Because different lines will be staggered, it's somewhat hard to see.
Lines uint8 `json:"lines"`
// CellsPerLine is the rough number of columns (in PointyTop orientation) or rows (in FlatTop orientation).
// This is the number of cells joined together, flat-edge to flat-edge, in each line.
CellsPerLine uint8 `json:"cellsPerLine"`
// Layout is the orientation and line parity used to display the map.
Layout Layout `json:"layout"`
// Layer contains the actual map data.
// Layer itself is a slice with Lines elements, each of which is a line;
// each of those lines is a slice of CellsPerLine cells.
Layer HexLayer `json:"layer"`
}
func NewHexMap(layout Layout, lines uint8, cellsPerLine uint8) *HexMap {
layer := make(HexLayer, lines)
for index := range layer {
line := make(HexLine, cellsPerLine)
for index := range line {
line[index] = HexCell{
Color: Color{
R: 255,
G: 255,
B: 255,
A: 255,
},
}
}
layer[index] = line
}
return &HexMap{
XID: xid.New(),
Layout: layout,
Lines: lines,
CellsPerLine: cellsPerLine,
Layer: layer,
}
}
func (m HexMap) MarshalLogObject(encoder zapcore.ObjectEncoder) error {
encoder.AddString("id", m.XID.String())
encoder.AddUint8("lines", m.Lines)
encoder.AddUint8("cellsPerLine", m.CellsPerLine)
displayModeErr := encoder.AddObject("layout", m.Layout)
lineCellsErr := encoder.AddArray("lineCells", m.Layer)
if displayModeErr != nil {
return displayModeErr
} else {
return lineCellsErr
}
}
// Copy creates a deep copy of this HexMap.
func (m HexMap) Copy() HexMap {
return HexMap{
XID: m.XID,
Lines: m.Lines,
CellsPerLine: m.CellsPerLine,
Layout: m.Layout,
Layer: m.Layer.Copy(),
}
}