-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add simulation actor and game connection actors
- Loading branch information
Showing
15 changed files
with
412 additions
and
97 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import gleam/dict.{type Dict} | ||
import gleam/otp/task | ||
import model/core | ||
|
||
pub type DataError { | ||
DataError | ||
} | ||
|
||
pub type RoomTemplate { | ||
RoomTemplate( | ||
name: String, | ||
description: String, | ||
exits: Dict(core.Direction, core.Location), | ||
) | ||
} | ||
|
||
pub type RegionTemplate { | ||
RegionTemplate(name: String, rooms: Dict(String, RoomTemplate)) | ||
} | ||
|
||
fn add_room(region: RegionTemplate, id: String, room: RoomTemplate) { | ||
RegionTemplate(..region, rooms: dict.insert(region.rooms, id, room)) | ||
} | ||
|
||
pub type WorldTemplate { | ||
WorldTemplate(regions: Dict(String, RegionTemplate)) | ||
} | ||
|
||
fn add_region(world: WorldTemplate, id: String, region: RegionTemplate) { | ||
WorldTemplate(regions: dict.insert(world.regions, id, region)) | ||
} | ||
|
||
pub fn load_world() -> Result(WorldTemplate, DataError) { | ||
let handle = | ||
task.async(fn() { | ||
// this will eventually call out to the file system | ||
Ok( | ||
WorldTemplate(regions: dict.new()) | ||
|> add_region( | ||
"testregion", | ||
RegionTemplate(name: "Test Region", rooms: dict.new()) | ||
|> add_room( | ||
"testroom", | ||
RoomTemplate( | ||
name: "Test Room", | ||
description: "An empty test room", | ||
exits: dict.new(), | ||
), | ||
), | ||
), | ||
) | ||
}) | ||
|
||
task.await(handle, 60_000) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
pub type Direction { | ||
North | ||
East | ||
South | ||
West | ||
NorthEast | ||
SouthEast | ||
SouthWest | ||
NorthWest | ||
Up | ||
Down | ||
} | ||
|
||
pub type Location { | ||
Location(region: String, room: String) | ||
} |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import gleam/int | ||
import gleam/option.{None} | ||
import model/entity | ||
|
||
pub fn create_guest_player() { | ||
entity.new([ | ||
entity.Named(name: "Guest" <> int.to_string(int.random(99_999))), | ||
entity.Physical(hp: 10, size: 0), | ||
entity.PaperDollHead(entity: None), | ||
entity.PaperDollBack(entity: None), | ||
entity.PaperDollChest(entity: None), | ||
entity.PaperDollPrimaryHand(entity: None), | ||
entity.PaperDollOffHand(entity: None), | ||
entity.PaperDollLegs(entity: None), | ||
entity.PaperDollFeet(entity: None), | ||
]) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import gleam/erlang/process.{type Subject} | ||
import gleam/otp/actor | ||
import data/world | ||
import gleam/io | ||
|
||
type State { | ||
State(world_template: world.WorldTemplate) | ||
} | ||
|
||
/// Control message are sent by top level actors to control the sim directly | ||
pub type Control { | ||
JoinAsGuest(Subject(Update)) | ||
Tick | ||
Shutdown | ||
} | ||
|
||
/// Commands are sent from game connections to entities | ||
pub type Command { | ||
Look | ||
} | ||
|
||
/// Updates are sent from entities to game connections | ||
pub type Update { | ||
CommandSubject(Subject(Command)) | ||
// RoomDescription | ||
} | ||
|
||
pub fn start() -> Result(Subject(Control), actor.StartError) { | ||
// data loading | ||
let assert Ok(world) = world.load_world() | ||
|
||
actor.start(State(world), handle_message) | ||
} | ||
|
||
pub fn stop(subject: Subject(Control)) { | ||
process.send(subject, Shutdown) | ||
} | ||
|
||
fn handle_message(message: Control, state: State) -> actor.Next(Control, State) { | ||
case message { | ||
Tick -> { | ||
// io.println("tick") | ||
actor.continue(state) | ||
} | ||
|
||
JoinAsGuest(subject) -> { | ||
io.debug("continue as guest") | ||
actor.continue(state) | ||
} | ||
|
||
Shutdown -> actor.Stop(process.Normal) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
// import gleam/dict.{type Dict} | ||
// import model/entity.{type Entity} | ||
|
||
// pub type Direction { | ||
// North | ||
// East | ||
// South | ||
// West | ||
// NorthEast | ||
// SouthEast | ||
// SouthWest | ||
// NorthWest | ||
// Up | ||
// Down | ||
// } | ||
|
||
// pub type Location { | ||
// Location(region: String, room: String) | ||
// } | ||
|
||
// pub type RoomTemplate { | ||
// RoomTemplate(name: String, description: String, exits: Dict(Direction, Exit)) | ||
// } | ||
|
||
// pub type RegionTemplate { | ||
// RegionTemplate(name: String, rooms: Dict(String, RoomTemplate)) | ||
// } | ||
|
||
// pub type Room { | ||
// Room(location: Location, entities: List(Entity)) | ||
// } | ||
|
||
// pub type Region { | ||
// Region(name: String, rooms: Dict(String, Room)) | ||
// RegionInstance(name: String, rooms: Dict(String, Room)) | ||
// } | ||
|
||
// pub type World { | ||
// World(templates: Dict(String, RegionTemplate), regions: Dict(String, Region)) | ||
// } |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
import gleam/erlang/process.{type Selector, type Subject} | ||
import gleam/option.{None, Some} | ||
import gleam/otp/actor | ||
import telnet/states/states | ||
import telnet/states/menu | ||
import model/simulation | ||
import gleam/function | ||
import glisten | ||
|
||
pub type Message { | ||
Dimensions(Int, Int) | ||
Data(String) | ||
Update(simulation.Update) | ||
} | ||
|
||
pub fn start( | ||
parent_subject: Subject(Subject(Message)), | ||
sim_subject: Subject(simulation.Control), | ||
conn: glisten.Connection(BitArray), | ||
) -> Result(Subject(Message), actor.StartError) { | ||
actor.start_spec(actor.Spec( | ||
init: fn() { | ||
let tcp_subject = process.new_subject() | ||
process.send(parent_subject, tcp_subject) | ||
|
||
let selector = | ||
process.new_selector() | ||
|> process.selecting(tcp_subject, function.identity) | ||
|
||
actor.Ready( | ||
#( | ||
tcp_subject, | ||
selector, | ||
states.FirstIAC( | ||
conn: conn, | ||
dimensions: states.ClientDimensions(80, 24), | ||
directory: states.Directory( | ||
sim_subject: sim_subject, | ||
command_subject: None, | ||
), | ||
), | ||
), | ||
selector, | ||
) | ||
}, | ||
init_timeout: 1000, | ||
loop: handle_message, | ||
)) | ||
} | ||
|
||
fn handle_message( | ||
message: Message, | ||
state: #(Subject(Message), Selector(Message), states.State), | ||
) -> actor.Next(Message, #(Subject(Message), Selector(Message), states.State)) { | ||
case message { | ||
Dimensions(width, height) -> | ||
handle_dimensions(state, width, height) | ||
|> actor.continue() | ||
Data(str) -> | ||
handle_data(state, str) | ||
|> actor.continue() | ||
Update(update) -> | ||
handle_update(state, update) | ||
|> actor.continue() | ||
} | ||
} | ||
|
||
fn handle_dimensions( | ||
state: #(Subject(Message), Selector(Message), states.State), | ||
width: Int, | ||
height: Int, | ||
) -> #(Subject(Message), Selector(Message), states.State) { | ||
#(state.0, state.1, case state.2 { | ||
states.FirstIAC(conn, _, directory) -> | ||
states.Menu(conn, states.ClientDimensions(width, height), directory) | ||
|> menu.on_enter() | ||
states.Menu(conn, _, directory) -> | ||
states.Menu(conn, states.ClientDimensions(width, height), directory) | ||
states.InWorld(conn, _, directory) -> | ||
states.InWorld(conn, states.ClientDimensions(width, height), directory) | ||
}) | ||
} | ||
|
||
fn handle_data( | ||
state: #(Subject(Message), Selector(Message), states.State), | ||
str: String, | ||
) -> #(Subject(Message), Selector(Message), states.State) { | ||
case state.2 { | ||
states.FirstIAC(_, _, _) -> state | ||
states.Menu(_, _, _) -> { | ||
let #(new_state, command_subject) = | ||
state.2 | ||
|> menu.handle_input(str) | ||
case command_subject { | ||
Some(subject) -> #( | ||
state.0, | ||
process.new_selector() | ||
|> process.selecting(state.0, function.identity) | ||
|> process.selecting(subject, fn(update) { Update(update) }), | ||
new_state, | ||
) | ||
None -> #(state.0, state.1, new_state) | ||
} | ||
} | ||
states.InWorld(_, _, _) -> state | ||
} | ||
} | ||
|
||
fn handle_update( | ||
state: #(Subject(Message), Selector(Message), states.State), | ||
update: simulation.Update, | ||
) -> #(Subject(Message), Selector(Message), states.State) { | ||
case update { | ||
simulation.CommandSubject(subject) -> #( | ||
state.0, | ||
state.1, | ||
state.2 | ||
|> states.with_command_subject(subject), | ||
) | ||
} | ||
} |
Oops, something went wrong.