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/action/action.go

125 lines
3.7 KiB

package action
import (
"errors"
"git.reya.zone/reya/hexmap/server/state"
"go.uber.org/zap/zapcore"
)
var (
// ErrNoOp is returned when an action has no effect.
ErrNoOp = errors.New("action's effects were already applied, or it's an empty action")
// ErrNoTransparentColors is returned when a user tries to set their active color or a cell color to transparent.
// Transparent here is defined as having an alpha component of less than 15 (0xF).
ErrNoTransparentColors = errors.New("transparent colors not allowed")
)
// Action is the interface for actions that can be shared between clients, or between the server and a client.
type Action interface {
zapcore.ObjectMarshaler
// Apply causes the action's effects to be applied to s, mutating it in place.
// All Actions must conform to the standard that if an action can't be correctly applied, or if it would
// have no effect, it returns an error without changing s.
// If an action can be correctly applied but would have no effect, it should return ErrNoOp.
// If an action is correctly applied and has an effect, it should return nil.
Apply(s *state.Synced) error
}
type Client interface {
Server
// ToClientPB converts the action into a client action protocol buffer.
ToClientPB() *ClientActionPB
}
type Server interface {
Action
// ToServerPB converts the action into a server action protocol buffer.
ToServerPB() *ServerActionPB
}
func serverPBFromClient(c Client) *ServerActionPB {
return &ServerActionPB{
Action: &ServerActionPB_Client{Client: c.ToClientPB()},
}
}
type ServerSlice []Server
func (s ServerSlice) MarshalLogArray(encoder zapcore.ArrayEncoder) error {
var finalErr error = nil
for _, a := range s {
err := encoder.AppendObject(a)
if err != nil && finalErr == nil {
finalErr = err
}
}
return finalErr
}
// CellColor is the action sent when a cell of the map has been colored a different color.
type CellColor struct {
// At is the location of the cell in storage coordinates.
At state.StorageCoordinates `json:"at"`
// Color is the color the cell has been changed to.
Color state.Color `json:"color"`
}
func (c CellColor) MarshalLogObject(encoder zapcore.ObjectEncoder) error {
encoder.AddString("type", "CellColor")
err := encoder.AddObject("at", c.At)
encoder.AddString("color", c.Color.String())
return err
}
// Apply sets the target cell's color, or returns ErrNoOp if it can't.
func (c CellColor) Apply(s *state.Synced) error {
if c.Color.A < 0xF {
return ErrNoTransparentColors
}
cell, err := s.Map.Layer.GetCellAt(c.At)
if err != nil {
return err
}
if cell.Color == c.Color {
return ErrNoOp
}
cell.Color = c.Color
return nil
}
// UserActiveColor is the action sent when the user's current color, the one being painted with, changes.
type UserActiveColor struct {
// Color is the color that is now active.
Color state.Color `json:"color"`
}
func (c UserActiveColor) MarshalLogObject(encoder zapcore.ObjectEncoder) error {
encoder.AddString("type", "UserActiveColor")
encoder.AddString("color", c.Color.String())
return nil
}
// Apply sets the user's active color, or returns ErrNoOp if it can't.
func (c UserActiveColor) Apply(s *state.Synced) error {
if c.Color.A < 0xF {
return ErrNoTransparentColors
}
if s.User.ActiveColor == c.Color {
return ErrNoOp
}
s.User.ActiveColor = c.Color
return nil
}
// IDed contains a pair of ID and Action, as sent by the client.
type IDed struct {
// ID contains the arbitrary ID that was sent by the client, for identifying the action in future messages.
ID uint32 `json:"id"`
// Action contains the action that was actually being sent.
Action Client `json:"action"`
}
func (i IDed) MarshalLogObject(encoder zapcore.ObjectEncoder) error {
encoder.AddUint32("id", i.ID)
return encoder.AddObject("action", i.Action)
}