working on a major refactor

master
Jordan Orelli 4 years ago
parent 68eb250d59
commit 5ad36dbe69

@ -0,0 +1,82 @@
package app
import (
"github.com/gdamore/tcell/v2"
"github.com/jordanorelli/astro-domu/internal/server/sim"
"github.com/jordanorelli/astro-domu/internal/wire"
"github.com/jordanorelli/blammo"
)
type gameView struct {
*blammo.Log
width int
height int
// entities map[int]wire.Entity
}
func (v *gameView) handleEvent(ui *UI, e tcell.Event) bool {
switch t := e.(type) {
case *tcell.EventKey:
key := t.Key()
if key == tcell.KeyRune {
switch t.Rune() {
case 'w':
v.move(ui, 0, -1)
case 'a':
v.move(ui, -1, 0)
case 's':
v.move(ui, 0, 1)
case 'd':
v.move(ui, 1, 0)
}
}
default:
// ui.Debug("screen saw unhandled event of type %T", e)
}
return true
}
func (v *gameView) notify(wv wire.Value) {
v.Error("ignoring notifications at the moment: %v", wv)
// if e, ok := v.(*wire.Entity); ok {
// m.entities[e.ID] = *e
// }
}
func (v *gameView) move(ui *UI, dx, dy int) {
_, err := ui.client.Send(sim.Move{dx, dy})
if err != nil {
return
}
// e := reply.Body.(*wire.Entity)
// v.entities[e.ID] = *e
}
func (v *gameView) draw(ui *UI) {
offset := point{1, 1}
// fill in background dots first
for x := 0; x < v.width; x++ {
for y := 0; y < v.height; y++ {
ui.screen.SetContent(x+offset.x, y+offset.y, '·', nil, tcell.StyleDefault)
}
}
// frame it
ui.screen.SetContent(offset.x-1, offset.y-1, '┌', nil, tcell.StyleDefault)
ui.screen.SetContent(offset.x+v.width, offset.y-1, '┐', nil, tcell.StyleDefault)
ui.screen.SetContent(offset.x-1, offset.y+v.height, '└', nil, tcell.StyleDefault)
ui.screen.SetContent(offset.x+v.width, offset.y+v.height, '┘', nil, tcell.StyleDefault)
for x := 0; x < v.width; x++ {
ui.screen.SetContent(x+offset.x, offset.y-1, '─', nil, tcell.StyleDefault)
ui.screen.SetContent(x+offset.x, offset.y+v.height, '─', nil, tcell.StyleDefault)
}
for y := 0; y < v.height; y++ {
ui.screen.SetContent(offset.x-1, y+offset.y, '│', nil, tcell.StyleDefault)
ui.screen.SetContent(offset.x+v.width, y+offset.y, '│', nil, tcell.StyleDefault)
}
// for _, e := range v.entities {
// ui.screen.SetContent(e.Position[0]+offset.x, e.Position[1]+offset.y, e.Glyph, nil, tcell.StyleDefault)
// }
}

@ -5,8 +5,6 @@ import (
"github.com/gdamore/tcell/v2"
"github.com/jordanorelli/astro-domu/internal/exit"
"github.com/jordanorelli/astro-domu/internal/server"
"github.com/jordanorelli/astro-domu/internal/server/sim"
"github.com/jordanorelli/astro-domu/internal/wire"
"github.com/jordanorelli/blammo"
)
@ -27,27 +25,28 @@ func (ui *UI) Run() {
return
}
res, err := ui.client.Send(server.Login{Name: ui.PlayerName})
res, err := ui.client.Send(wire.Login{Name: ui.PlayerName})
if err != nil {
ui.Error("login error: %v", err)
return
}
welcome, ok := res.Body.(*sim.Welcome)
welcome, ok := res.Body.(*wire.Welcome)
if !ok {
ui.Error("unexpected initial message of type %t", res.Body)
return
}
ui.Info("spawned into room %s", welcome.Room)
entities := make(map[int]sim.Entity, len(welcome.Contents))
for _, e := range welcome.Contents {
entities[e.ID] = e
}
ui.view = &roomDisplay{
width: welcome.Size[0],
height: welcome.Size[1],
entities: entities,
// entities := make(map[int]sim.Entity, len(welcome.Contents))
// for _, e := range welcome.Contents {
// entities[e.ID] = e
// }
ui.view = &gameView{
Log: ui.Child("game-view"),
width: welcome.Room.Width,
height: welcome.Room.Height,
// entities: entities,
}
ui.Info("running ui")
if ui.handleUserInput() {

@ -2,7 +2,6 @@ package app
import (
"github.com/gdamore/tcell/v2"
"github.com/jordanorelli/astro-domu/internal/server/sim"
"github.com/jordanorelli/astro-domu/internal/wire"
)
@ -11,75 +10,3 @@ type view interface {
notify(wire.Value)
draw(*UI)
}
type roomDisplay struct {
width int
height int
entities map[int]sim.Entity
}
func (m *roomDisplay) handleEvent(ui *UI, e tcell.Event) bool {
switch v := e.(type) {
case *tcell.EventKey:
key := v.Key()
if key == tcell.KeyRune {
switch v.Rune() {
case 'w':
m.move(ui, 0, -1)
case 'a':
m.move(ui, -1, 0)
case 's':
m.move(ui, 0, 1)
case 'd':
m.move(ui, 1, 0)
}
}
default:
// ui.Debug("screen saw unhandled event of type %T", e)
}
return true
}
func (m *roomDisplay) notify(v wire.Value) {
if e, ok := v.(*sim.Entity); ok {
m.entities[e.ID] = *e
}
}
func (m *roomDisplay) move(ui *UI, dx, dy int) {
reply, err := ui.client.Send(sim.Move{dx, dy})
if err != nil {
return
}
e := reply.Body.(*sim.Entity)
m.entities[e.ID] = *e
}
func (m *roomDisplay) draw(ui *UI) {
offset := point{1, 1}
// fill in background dots first
for x := 0; x < m.width; x++ {
for y := 0; y < m.height; y++ {
ui.screen.SetContent(x+offset.x, y+offset.y, '·', nil, tcell.StyleDefault)
}
}
// frame it
ui.screen.SetContent(offset.x-1, offset.y-1, '┌', nil, tcell.StyleDefault)
ui.screen.SetContent(offset.x+m.width, offset.y-1, '┐', nil, tcell.StyleDefault)
ui.screen.SetContent(offset.x-1, offset.y+m.height, '└', nil, tcell.StyleDefault)
ui.screen.SetContent(offset.x+m.width, offset.y+m.height, '┘', nil, tcell.StyleDefault)
for x := 0; x < m.width; x++ {
ui.screen.SetContent(x+offset.x, offset.y-1, '─', nil, tcell.StyleDefault)
ui.screen.SetContent(x+offset.x, offset.y+m.height, '─', nil, tcell.StyleDefault)
}
for y := 0; y < m.height; y++ {
ui.screen.SetContent(offset.x-1, y+offset.y, '│', nil, tcell.StyleDefault)
ui.screen.SetContent(offset.x+m.width, y+offset.y, '│', nil, tcell.StyleDefault)
}
for _, e := range m.entities {
ui.screen.SetContent(e.Position[0]+offset.x, e.Position[1]+offset.y, e.Glyph, nil, tcell.StyleDefault)
}
}

@ -0,0 +1,26 @@
package math
import (
"encoding/json"
)
type Vec struct {
X int
Y int
}
func (v Vec) MarshalJSON() ([]byte, error) {
return json.Marshal([2]int{v.X, v.Y})
}
func (v *Vec) UnmarshalJSON(b []byte) error {
var raw [2]int
if err := json.Unmarshal(b, &raw); err != nil {
return err
}
v.X = raw[0]
v.Y = raw[1]
return nil
}
func (v Vec) Add(v2 Vec) Vec { return Vec{v.X + v2.X, v.Y + v2.Y} }

@ -92,7 +92,7 @@ func (sn *session) read() {
sn.Info("received message of type %T", req.Body)
switch v := req.Body.(type) {
case *Login:
case *wire.Login:
sn.Name = v.Name
sn.world.Inbox <- sim.Request{
From: sn.Name,
@ -141,13 +141,3 @@ func (sn *session) sendResponse(res wire.Response) error {
sn.Child("sent-frame").Info(string(payload))
return nil
}
type Login struct {
Name string `json:"name"`
}
func (Login) NetTag() string { return "login" }
func init() {
wire.Register(func() wire.Value { return new(Login) })
}

@ -3,22 +3,16 @@ package sim
import (
"time"
"github.com/jordanorelli/astro-domu/internal/wire"
"github.com/jordanorelli/astro-domu/internal/math"
)
type Entity struct {
type entity struct {
ID int `json:"id"`
Position [2]int `json:"pos"`
Position math.Vec `json:"pos"`
Glyph rune `json:"glyph"`
behavior
}
func (Entity) NetTag() string { return "entity" }
func init() {
wire.Register(func() wire.Value { return new(Entity) })
}
type behavior interface {
// update is the standard tick function
update(time.Duration)

@ -1,6 +1,7 @@
package sim
import (
"github.com/jordanorelli/astro-domu/internal/math"
"github.com/jordanorelli/astro-domu/internal/wire"
"github.com/jordanorelli/blammo"
)
@ -12,31 +13,35 @@ type player struct {
name string
outbox chan wire.Response
pending []Request
entity *Entity
entity *entity
}
type Move [2]int
type Move math.Vec
func (Move) NetTag() string { return "move" }
func (m *Move) exec(r *room, p *player, seq int) result {
pos := p.entity.Position
target := [2]int{pos[0] + m[0], pos[1] + m[1]}
target := pos.Add(math.Vec(*m))
p.Info("running move for player %s from %v to %v", p.name, *m, target)
if target[0] >= r.width || target[0] < 0 {
return result{reply: wire.Errorf("target cell (%d, %d) is out of bounds", target[0], target[1])}
if target.X >= r.width || target.X < 0 {
return result{reply: wire.Errorf("target cell (%d, %d) is out of bounds", target.X, target.Y)}
}
if target[1] >= r.height || target[1] < 0 {
return result{reply: wire.Errorf("target cell (%d, %d) is out of bounds", target[0], target[1])}
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)}
}
n := target[1]*r.width + target[0]
n := target.X*r.width + target.Y
if r.tiles[n].here != nil {
return result{reply: wire.Errorf("target cell (%d, %d) is occupied", target[0], target[1])}
return result{reply: wire.Errorf("target cell (%d, %d) is occupied", target.X, target.Y)}
}
r.tiles[p.entity.Position[1]*r.width+p.entity.Position[0]].here = nil
r.tiles[p.entity.Position.X*r.width+p.entity.Position.Y].here = nil
p.entity.Position = target
r.tiles[n].here = p.entity
return result{reply: p.entity, announce: p.entity}
e := wire.Entity{
Position: p.entity.Position,
Glyph: '@',
}
return result{reply: e, announce: e}
}
// SpawnPlayer is a request to spawn a player
@ -64,9 +69,9 @@ func (s *SpawnPlayer) exec(r *room, _ *player, seq int) result {
name: s.Name,
outbox: s.Outbox,
pending: make([]Request, 0, 32),
entity: &Entity{
entity: &entity{
ID: lastEntityID,
Position: [2]int{0, 0},
Position: math.Vec{0, 0},
Glyph: '@',
behavior: doNothing{},
},
@ -78,13 +83,11 @@ func (s *SpawnPlayer) exec(r *room, _ *player, seq int) result {
return result{}
}
return result{
reply: Welcome{
Room: r.name,
Size: [2]int{r.width, r.height},
Contents: r.allEntities(),
},
}
var welcome wire.Welcome
welcome.Room.Width = r.width
welcome.Room.Height = r.height
welcome.Room.Origin = math.Vec{0, 0}
return result{reply: welcome}
}
func (SpawnPlayer) NetTag() string { return "player/spawn" }
@ -97,33 +100,7 @@ type PlayerSpawned struct {
func (PlayerSpawned) NetTag() string { return "player/spawned" }
type Welcome struct {
Room string `json:"room"`
Size [2]int `json:"size"`
Contents []Entity `json:"contents"`
}
/*
{
"name": "foyer",
"width": 10,
"height": 10,
"contents": [
[5, 3, 10],
],
"entities": [
[3, "pawn", {"name": "bones"}],
[10, "pawn", {"name": "steve"}]
]
}
*/
func (Welcome) NetTag() string { return "player/welcome" }
func init() {
wire.Register(func() wire.Value { return new(Move) })
wire.Register(func() wire.Value { return new(Welcome) })
// wire.Register(func() wire.Value { return new(pawn) })
}

@ -39,8 +39,8 @@ func (r *room) update(dt time.Duration) {
}
}
func (r *room) allEntities() []Entity {
all := make([]Entity, 0, 4)
func (r *room) allEntities() []entity {
all := make([]entity, 0, 4)
for _, t := range r.tiles {
if t.here != nil {
all = append(all, *t.here)

@ -2,5 +2,5 @@ package sim
type tile struct {
floor floor
here *Entity
here *entity
}

@ -3,6 +3,7 @@ package sim
import (
"time"
"github.com/jordanorelli/astro-domu/internal/math"
"github.com/jordanorelli/astro-domu/internal/wire"
"github.com/jordanorelli/blammo"
)
@ -28,9 +29,9 @@ func NewWorld(log *blammo.Log) *World {
tiles: make([]tile, 100),
players: make(map[string]*player),
}
foyer.tiles[55].here = &Entity{
foyer.tiles[55].here = &entity{
ID: 777,
Position: [2]int{5, 5},
Position: math.Vec{5, 5},
Glyph: 'd',
behavior: doNothing{},
}

@ -1 +1,16 @@
package wire
import (
"github.com/jordanorelli/astro-domu/internal/math"
)
type Entity struct {
Position math.Vec `json:"position"`
Glyph rune `json:"glyph"`
}
func (Entity) NetTag() string { return "entity" }
func init() {
Register(func() Value { return new(Entity) })
}

@ -0,0 +1,11 @@
package wire
type Login struct {
Name string `json:"name"`
}
func (Login) NetTag() string { return "login" }
func init() {
Register(func() Value { return new(Login) })
}

@ -0,0 +1,20 @@
package wire
import (
"github.com/jordanorelli/astro-domu/internal/math"
)
type Welcome struct {
Room struct {
Origin math.Vec `json:"origin"`
Width int `json:"width"`
Height int `json:"height"`
} `json:"room"`
Entities map[int]Entity `json:"entities"`
}
func (Welcome) NetTag() string { return "welcome" }
func init() {
Register(func() Value { return new(Welcome) })
}
Loading…
Cancel
Save