i think i'm making it worse now

master
Jordan Orelli 4 years ago
parent 5ad36dbe69
commit cd96c66e6b

@ -2,6 +2,7 @@ package app
import ( import (
"github.com/gdamore/tcell/v2" "github.com/gdamore/tcell/v2"
"github.com/jordanorelli/astro-domu/internal/math"
"github.com/jordanorelli/astro-domu/internal/server/sim" "github.com/jordanorelli/astro-domu/internal/server/sim"
"github.com/jordanorelli/astro-domu/internal/wire" "github.com/jordanorelli/astro-domu/internal/wire"
"github.com/jordanorelli/blammo" "github.com/jordanorelli/blammo"
@ -9,9 +10,12 @@ import (
type gameView struct { type gameView struct {
*blammo.Log *blammo.Log
roomName string
width int width int
height int height int
// entities map[int]wire.Entity me wire.Entity
allRooms map[string]wire.Room
allEntities map[int]wire.Entity
} }
func (v *gameView) handleEvent(ui *UI, e tcell.Event) bool { func (v *gameView) handleEvent(ui *UI, e tcell.Event) bool {
@ -38,18 +42,30 @@ func (v *gameView) handleEvent(ui *UI, e tcell.Event) bool {
func (v *gameView) notify(wv wire.Value) { func (v *gameView) notify(wv wire.Value) {
v.Error("ignoring notifications at the moment: %v", wv) v.Error("ignoring notifications at the moment: %v", wv)
// if e, ok := v.(*wire.Entity); ok { switch z := wv.(type) {
// m.entities[e.ID] = *e case *wire.UpdateEntity:
// } if z.Room == v.roomName {
v.Info("we want to read this one: %v", z)
}
}
} }
func (v *gameView) move(ui *UI, dx, dy int) { func (v *gameView) move(ui *UI, dx, dy int) {
_, err := ui.client.Send(sim.Move{dx, dy}) reply, err := ui.client.Send(sim.Move{dx, dy})
if err != nil { if err != nil {
return return
} }
// e := reply.Body.(*wire.Entity)
// v.entities[e.ID] = *e e := reply.Body.(*wire.UpdateEntity)
// ughhhhhh
v.me = wire.Entity{
ID: e.ID,
Position: e.Position,
Glyph: e.Glyph,
}
v.allEntities[e.ID] = v.me
// jfc this sucks
v.allRooms[v.roomName].Entities[e.ID] = v.me
} }
func (v *gameView) draw(ui *UI) { func (v *gameView) draw(ui *UI) {
@ -76,7 +92,8 @@ func (v *gameView) draw(ui *UI) {
ui.screen.SetContent(offset.x+v.width, y+offset.y, '│', nil, tcell.StyleDefault) ui.screen.SetContent(offset.x+v.width, y+offset.y, '│', nil, tcell.StyleDefault)
} }
// for _, e := range v.entities { for _, e := range v.allRooms[v.roomName].Entities {
// ui.screen.SetContent(e.Position[0]+offset.x, e.Position[1]+offset.y, e.Glyph, nil, tcell.StyleDefault) pos := e.Position.Add(math.Vec{1, 1})
// } ui.screen.SetContent(pos.X, pos.Y, e.Glyph, nil, tcell.StyleDefault)
}
} }

@ -36,18 +36,25 @@ func (ui *UI) Run() {
ui.Error("unexpected initial message of type %t", res.Body) ui.Error("unexpected initial message of type %t", res.Body)
return return
} }
ui.Info("spawned into room %s", welcome.Room) ui.Info("welcome: %v", welcome)
meta := welcome.Players[ui.PlayerName]
// entities := make(map[int]sim.Entity, len(welcome.Contents)) room := welcome.Rooms[meta.Room]
// for _, e := range welcome.Contents { allEntities := make(map[int]wire.Entity)
// entities[e.ID] = e for _, r := range welcome.Rooms {
// } for id, e := range r.Entities {
allEntities[id] = e
}
}
ui.view = &gameView{ ui.view = &gameView{
Log: ui.Child("game-view"), Log: ui.Child("game-view"),
width: welcome.Room.Width, roomName: room.Name,
height: welcome.Room.Height, width: room.Width(),
// entities: entities, height: room.Height(),
me: room.Entities[meta.Avatar],
allRooms: welcome.Rooms,
allEntities: allEntities,
} }
ui.Info("running ui") ui.Info("running ui")
if ui.handleUserInput() { if ui.handleUserInput() {
ui.Info("user requested close") ui.Info("user requested close")

@ -0,0 +1,8 @@
package math
func Abs(n int) int {
if n >= 0 {
return n
}
return -n
}

@ -0,0 +1,35 @@
package math
import "encoding/json"
type Bounds struct {
Min Vec `json:"min"`
Max Vec `json:"max"`
}
func CreateBounds(width, height int) Bounds {
return Bounds{
Min: Vec{0, 0},
Max: Vec{width - 1, height - 1},
}
}
func (b Bounds) Width() int { return Abs(b.Max.X - b.Min.X) }
func (b Bounds) Height() int { return Abs(b.Max.Y - b.Min.Y) }
func (b Bounds) Area() int { return b.Width() * b.Height() }
func (b Bounds) Contains(v Vec) bool {
return v.X >= b.Min.X && v.X <= b.Max.X && v.Y >= b.Min.Y && v.Y <= b.Max.Y
}
func (b Bounds) MarshalJSON() ([]byte, error) { return json.Marshal([2]Vec{b.Min, b.Max}) }
func (b *Bounds) UnmarshalJSON(buf []byte) error {
var raw [2]Vec
if err := json.Unmarshal(buf, &raw); err != nil {
return err
}
b.Min = raw[0]
b.Max = raw[1]
return nil
}

@ -13,7 +13,7 @@ type player struct {
name string name string
outbox chan wire.Response outbox chan wire.Response
pending []Request pending []Request
entity *entity avatar *entity
} }
type Move math.Vec type Move math.Vec
@ -21,24 +21,25 @@ type Move math.Vec
func (Move) NetTag() string { return "move" } func (Move) NetTag() string { return "move" }
func (m *Move) exec(r *room, p *player, seq int) result { func (m *Move) exec(r *room, p *player, seq int) result {
pos := p.entity.Position pos := p.avatar.Position
target := pos.Add(math.Vec(*m)) target := pos.Add(math.Vec(*m))
p.Info("running move for player %s from %v to %v", p.name, *m, target) p.Info("running move for player %s from %v to %v", p.name, *m, target)
if target.X >= r.width || target.X < 0 { if !p.room.bounds.Contains(target) {
return result{reply: wire.Errorf("target cell (%d, %d) is out of bounds", target.X, target.Y)} return result{reply: wire.Errorf("target cell (%d, %d) is out of bounds", target.X, target.Y)}
} }
if target.Y >= r.height || target.Y < 0 {
return result{reply: wire.Errorf("target cell (%d, %d) is out of bounds", target.X, target.Y)} currentTile := r.getTile(pos)
} nextTile := r.getTile(target)
n := target.X*r.width + target.Y if nextTile.here != nil {
if r.tiles[n].here != nil {
return result{reply: wire.Errorf("target cell (%d, %d) is occupied", target.X, target.Y)} return result{reply: wire.Errorf("target cell (%d, %d) is occupied", target.X, target.Y)}
} }
r.tiles[p.entity.Position.X*r.width+p.entity.Position.Y].here = nil
p.entity.Position = target currentTile.here, nextTile.here = nil, p.avatar
r.tiles[n].here = p.entity p.avatar.Position = target
e := wire.Entity{ e := wire.UpdateEntity{
Position: p.entity.Position, Room: r.name,
ID: p.avatar.ID,
Position: p.avatar.Position,
Glyph: '@', Glyph: '@',
} }
return result{reply: e, announce: e} return result{reply: e, announce: e}
@ -63,30 +64,51 @@ func (s *SpawnPlayer) exec(r *room, _ *player, seq int) result {
} }
lastEntityID++ lastEntityID++
avatar := &entity{
ID: lastEntityID,
Position: math.Vec{0, 0},
Glyph: '@',
behavior: doNothing{},
}
p := &player{ p := &player{
Log: r.Log.Child("players").Child(s.Name), Log: r.Log.Child("players").Child(s.Name),
room: r, room: r,
name: s.Name, name: s.Name,
outbox: s.Outbox, outbox: s.Outbox,
pending: make([]Request, 0, 32), pending: make([]Request, 0, 32),
entity: &entity{ avatar: avatar,
ID: lastEntityID,
Position: math.Vec{0, 0},
Glyph: '@',
behavior: doNothing{},
},
} }
p.pending = append(p.pending, Request{Seq: seq, From: s.Name, Wants: s}) p.pending = append(p.pending, Request{Seq: seq, From: s.Name, Wants: s})
r.players[s.Name] = p r.players[s.Name] = p
r.tiles[0].here = p.entity r.tiles[0].here = p.avatar
s.queued = true s.queued = true
return result{} return result{}
} }
var welcome wire.Welcome welcome := wire.Welcome{
welcome.Room.Width = r.width Rooms: make(map[string]wire.Room),
welcome.Room.Height = r.height Players: make(map[string]wire.Player),
welcome.Room.Origin = math.Vec{0, 0} }
ents := make(map[int]wire.Entity)
for id, e := range r.allEntities() {
ents[id] = wire.Entity{
ID: id,
Position: e.Position,
Glyph: e.Glyph,
}
}
welcome.Rooms[r.name] = wire.Room{
Name: r.name,
Bounds: r.bounds,
Entities: ents,
}
for _, p := range r.players {
welcome.Players[p.name] = wire.Player{
Name: p.name,
Avatar: p.avatar.ID,
Room: r.name,
}
}
return result{reply: welcome} return result{reply: welcome}
} }
@ -102,5 +124,4 @@ func (PlayerSpawned) NetTag() string { return "player/spawned" }
func init() { func init() {
wire.Register(func() wire.Value { return new(Move) }) wire.Register(func() wire.Value { return new(Move) })
// wire.Register(func() wire.Value { return new(pawn) })
} }

@ -3,6 +3,7 @@ package sim
import ( import (
"time" "time"
"github.com/jordanorelli/astro-domu/internal/math"
"github.com/jordanorelli/astro-domu/internal/wire" "github.com/jordanorelli/astro-domu/internal/wire"
"github.com/jordanorelli/blammo" "github.com/jordanorelli/blammo"
) )
@ -11,8 +12,7 @@ type room struct {
*blammo.Log *blammo.Log
name string name string
origin point origin point
width int bounds math.Bounds
height int
tiles []tile tiles []tile
players map[string]*player players map[string]*player
} }
@ -39,11 +39,12 @@ func (r *room) update(dt time.Duration) {
} }
} }
func (r *room) allEntities() []entity { func (r *room) allEntities() map[int]*entity {
all := make([]entity, 0, 4) all := make(map[int]*entity, 4)
for _, t := range r.tiles { for _, t := range r.tiles {
if t.here != nil { if t.here != nil {
all = append(all, *t.here) e := t.here
all[e.ID] = e
} }
} }
return all return all
@ -60,3 +61,11 @@ func (r *room) removePlayer(name string) bool {
} }
return false return false
} }
func (r *room) getTile(pos math.Vec) *tile {
if !r.bounds.Contains(pos) {
return nil
}
n := pos.X*r.bounds.Width() + pos.Y
return &r.tiles[n]
}

@ -20,13 +20,13 @@ type World struct {
} }
func NewWorld(log *blammo.Log) *World { func NewWorld(log *blammo.Log) *World {
bounds := math.CreateBounds(10, 10)
foyer := room{ foyer := room{
Log: log.Child("foyer"), Log: log.Child("foyer"),
name: "foyer", name: "foyer",
origin: point{0, 0}, origin: point{0, 0},
width: 10, bounds: bounds,
height: 10, tiles: make([]tile, bounds.Area()),
tiles: make([]tile, 100),
players: make(map[string]*player), players: make(map[string]*player),
} }
foyer.tiles[55].here = &entity{ foyer.tiles[55].here = &entity{

@ -5,12 +5,23 @@ import (
) )
type Entity struct { type Entity struct {
ID int `json:"id"`
Position math.Vec `json:"position"` Position math.Vec `json:"position"`
Glyph rune `json:"glyph"` Glyph rune `json:"glyph"`
} }
func (Entity) NetTag() string { return "entity" } func (Entity) NetTag() string { return "entity" }
type UpdateEntity struct {
Room string `json:"room"`
ID int `json:"id"`
Position math.Vec `json:"position"`
Glyph rune `json:"glyph"`
}
func (UpdateEntity) NetTag() string { return "entity/updated" }
func init() { func init() {
Register(func() Value { return new(Entity) }) Register(func() Value { return new(Entity) })
Register(func() Value { return new(UpdateEntity) })
} }

@ -0,0 +1,7 @@
package wire
type Player struct {
Name string `json:"name"`
Room string `json:"room"`
Avatar int `json:"avatar"`
}

@ -0,0 +1,15 @@
package wire
import (
"github.com/jordanorelli/astro-domu/internal/math"
)
// Room represents a 2-dimensional coordinate space.
type Room struct {
Name string `json:"name"`
Bounds math.Bounds `json:"bounds"`
Entities map[int]Entity `json:"entities"`
}
func (r Room) Width() int { return r.Bounds.Width() }
func (r Room) Height() int { return r.Bounds.Height() }

@ -1,16 +1,8 @@
package wire package wire
import (
"github.com/jordanorelli/astro-domu/internal/math"
)
type Welcome struct { type Welcome struct {
Room struct { Rooms map[string]Room `json:"rooms"`
Origin math.Vec `json:"origin"` Players map[string]Player `json:"players"`
Width int `json:"width"`
Height int `json:"height"`
} `json:"room"`
Entities map[int]Entity `json:"entities"`
} }
func (Welcome) NetTag() string { return "welcome" } func (Welcome) NetTag() string { return "welcome" }

Loading…
Cancel
Save