diff --git a/.gitignore b/.gitignore
index 0026861..279a7dc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,3 +20,6 @@ _cgo_export.*
_testmain.go
*.exe
+
+.idea
+*.iml
\ No newline at end of file
diff --git a/doc.go b/doc.go
new file mode 100644
index 0000000..ce935de
--- /dev/null
+++ b/doc.go
@@ -0,0 +1,6 @@
+// berlin-mud project doc.go
+
+/*
+berlin-mud document
+*/
+package main
diff --git a/game/level.go b/game/level.go
new file mode 100644
index 0000000..cb54335
--- /dev/null
+++ b/game/level.go
@@ -0,0 +1,12 @@
+package game
+
+type Level struct {
+ Key string `xml:"key,attr"`
+ Name string `xml:"name"`
+ Directions []Direction `xml:"directions>direction"`
+}
+
+type Direction struct {
+ Station string `xml:"station,attr"`
+ Direction string `xml:",chardata"`
+}
diff --git a/game/player.go b/game/player.go
new file mode 100644
index 0000000..bd9453f
--- /dev/null
+++ b/game/player.go
@@ -0,0 +1,12 @@
+package game
+
+import "encoding/xml"
+
+type Player struct {
+ XMLName xml.Name `xml:"player"`
+ Nickname string `xml:"nickname,attr"`
+ Gamename string `xml:"name"`
+ Position string `xml:"position,attr"`
+ PlayerType string `xml:"type"`
+ Ch chan string
+}
diff --git a/game/server.go b/game/server.go
new file mode 100644
index 0000000..5f94dc7
--- /dev/null
+++ b/game/server.go
@@ -0,0 +1,110 @@
+package game
+
+import (
+ "encoding/xml"
+ "path/filepath"
+ "os"
+ "io/ioutil"
+ "log"
+)
+
+type Server struct {
+ name string
+ players map[string]Player
+ levels map[string]Level
+ workingdir string
+}
+
+func NewServer(servername string, serverdir string) *Server {
+ return &Server{
+ name: servername,
+ players: make(map[string]Player),
+ levels: make(map[string]Level),
+ workingdir: serverdir,
+ }
+}
+
+func (s *Server) LoadLevels() error {
+ log.Println("Loading levels ...")
+ levelWalker := func(path string, info os.FileInfo, err error) error {
+ if info.IsDir() {
+ return nil
+ }
+ fileContent, fileIoErr := ioutil.ReadFile(path)
+ if fileIoErr != nil {
+ log.Printf("\n")
+ log.Printf("File %s could not be loaded\n", path)
+ log.Printf("%v",fileIoErr)
+ //return fileIoErr
+ return nil
+ }
+ level := Level{}
+ if xmlerr := xml.Unmarshal(fileContent, &level); xmlerr != nil {
+ log.Printf("\n")
+ log.Printf("File %s could not be Unmarshaled\n", path, xmlerr)
+ log.Printf("%v",xmlerr)
+ //return xmlerr
+ return nil
+ }
+ log.Printf(" loaded: %s", info.Name())
+ s.addLevel(level)
+ return nil
+ }
+
+ filepath.Walk(s.workingdir+"/static/levels/", levelWalker)
+ return nil
+}
+
+func (s *Server) LoadPlayer(playerName string) bool {
+ playerFileName := s.workingdir+"/static/player/"+playerName+".player"
+
+ log.Println("Loading player %s", playerFileName)
+
+ fileContent, fileIoErr := ioutil.ReadFile(playerFileName)
+ if fileIoErr != nil {
+ log.Printf("\n")
+ log.Printf("File %s could not be loaded\n", playerFileName)
+ log.Printf("%v",fileIoErr)
+ //return fileIoErr
+ return false
+ }
+
+ player := Player{}
+ if xmlerr := xml.Unmarshal(fileContent, &player); xmlerr != nil {
+ log.Printf("\n")
+ log.Printf("File %s could not be Unmarshaled\n", playerFileName, xmlerr)
+ log.Printf("%v",xmlerr)
+ //return xmlerr
+ return false
+ }
+ log.Printf(" loaded: %s", player.Gamename)
+ s.addPlayer(player)
+
+ return true
+}
+
+func (s *Server) addLevel(level Level) error {
+ s.levels[level.Key] = level
+ return nil
+}
+
+func (s *Server) addPlayer(player Player) error {
+ s.players[player.Nickname] = player
+ return nil
+}
+
+func (s *Server) GetPlayerByNick(nickname string) (Player, bool) {
+ player,ok := s.players[nickname]
+ return player, ok
+}
+
+func (s *Server) GetRoom(key string) (Level, bool) {
+ level,ok := s.levels[key]
+ return level, ok
+}
+
+func (s *Server) GetName() string {
+ return s.name
+}
+
+
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..41b6d2d
--- /dev/null
+++ b/main.go
@@ -0,0 +1,156 @@
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "log"
+ "net"
+ "os"
+ "strings"
+ "github.com/woodworker/go-mud/game"
+)
+
+type Client struct {
+ conn net.Conn
+ nickname string
+ player game.Player
+ ch chan string
+}
+
+func main() {
+ workingdir, _ := os.Getwd()
+
+ log.Printf("Leveldir %s", workingdir+"/static/levels/")
+
+ server := game.NewServer("berlin-mud", workingdir)
+ server.LoadLevels()
+ log.Printf("%v", server)
+
+
+ ln, err := net.Listen("tcp", ":1337")
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+
+ msgchan := make(chan string)
+ addchan := make(chan Client)
+ rmchan := make(chan Client)
+
+ go handleMessages(msgchan, addchan, rmchan)
+
+ for {
+ conn, err := ln.Accept()
+ if err != nil {
+ fmt.Println(err)
+ continue
+ }
+
+ go handleConnection(conn, msgchan, addchan, rmchan, server)
+ }
+}
+
+func (c Client) ReadLinesInto(ch chan<- string) {
+ bufc := bufio.NewReader(c.conn)
+ for {
+ line, err := bufc.ReadString('\n')
+ if err != nil {
+ break
+ }
+ ch <- fmt.Sprintf("%s: %s", c.player.Gamename, line)
+ }
+}
+
+func (c Client) WriteLinesFrom(ch <-chan string) {
+ for msg := range ch {
+ _, err := io.WriteString(c.conn, msg)
+ if err != nil {
+ return
+ }
+ }
+}
+
+func promptNick(c net.Conn, bufc *bufio.Reader) string {
+ io.WriteString(c, "What is your nick? ")
+ nick, _, _ := bufc.ReadLine()
+ return string(nick)
+}
+
+func handleConnection(c net.Conn, msgchan chan<- string, addchan chan<- Client, rmchan chan<- Client, server *game.Server) {
+ bufc := bufio.NewReader(c)
+ defer c.Close()
+
+ io.WriteString(c, fmt.Sprintf("\033[1;30;41mWelcome to the Go-Mud Server %s!\033[0m\n\r", server.GetName()))
+
+ var nickname string
+ for {
+ nickname = promptNick(c, bufc)
+ ok := server.LoadPlayer(nickname)
+ if ok == true {
+ break
+ }
+ }
+
+ player, playerLoaded := server.GetPlayerByNick(nickname)
+
+ if !playerLoaded {
+ log.Println("problem getting user object")
+ io.WriteString(c, "Problem getting user object\n")
+ return
+ }
+
+ client := Client{
+ conn: c,
+ nickname: player.Nickname,
+ player: player,
+ ch: make(chan string),
+ }
+
+ if strings.TrimSpace(client.nickname) == "" {
+ log.Println("invalid username")
+ io.WriteString(c, "Invalid Username\n")
+ return
+ }
+
+ // Register user
+ addchan <- client
+ defer func() {
+ msgchan <- fmt.Sprintf("User %s left the chat room.\n\r", client.nickname)
+ log.Printf("Connection from %v closed.\n", c.RemoteAddr())
+ rmchan <- client
+ }()
+ io.WriteString(c, fmt.Sprintf("Welcome, %s!\n\n\r", client.nickname))
+
+ location, locationLoaded:= server.GetRoom( client.player.Position );
+
+ if locationLoaded {
+ io.WriteString(c, fmt.Sprintf("You are at: \033[1;33;40m%s\033[m\n\n\r", location.Name))
+ }
+
+ msgchan <- fmt.Sprintf("New user %s has joined the chat room.\n\r", client.nickname)
+
+ // I/O
+ go client.ReadLinesInto(msgchan)
+ client.WriteLinesFrom(client.ch)
+}
+
+func handleMessages(msgchan <-chan string, addchan <-chan Client, rmchan <-chan Client) {
+ clients := make(map[net.Conn]chan<- string)
+
+ for {
+ select {
+ case msg := <-msgchan:
+ log.Printf("New message: %s", msg)
+ for _, ch := range clients {
+ go func(mch chan<- string) { mch <- "\033[1;33;40m" + msg + "\033[m" }(ch)
+ }
+ case client := <-addchan:
+ log.Printf("New client: %v\n", client.conn)
+ clients[client.conn] = client.ch
+ case client := <-rmchan:
+ log.Printf("Client disconnects: %v\n", client.conn)
+ delete(clients, client.conn)
+ }
+ }
+}
diff --git a/static/levels/alex.lvl b/static/levels/alex.lvl
new file mode 100644
index 0000000..2bdbb1f
--- /dev/null
+++ b/static/levels/alex.lvl
@@ -0,0 +1,6 @@
+
+ Alexanderplatz
+
+ East
+
+
\ No newline at end of file
diff --git a/static/levels/jannowitzbruecke.lvl b/static/levels/jannowitzbruecke.lvl
new file mode 100644
index 0000000..4594005
--- /dev/null
+++ b/static/levels/jannowitzbruecke.lvl
@@ -0,0 +1,6 @@
+
+ Jannowitzbrücke
+
+ West
+
+
\ No newline at end of file
diff --git a/static/player/woodworker.player b/static/player/woodworker.player
new file mode 100644
index 0000000..b7a9184
--- /dev/null
+++ b/static/player/woodworker.player
@@ -0,0 +1,4 @@
+
+ The Mighty WooDWorkeR
+ Geek
+
\ No newline at end of file