Açıklama Yok

execution_context.go 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881
  1. package funmow
  2. import (
  3. "fmt"
  4. "regexp"
  5. "strings"
  6. "time"
  7. )
  8. type ExecutionContext struct {
  9. actor Object
  10. inbound chan PlayerEvent
  11. outbound chan PlayerEvent
  12. eventDistributor *EventDistributor
  13. db *DB
  14. factory *ObjectFactory
  15. forceContext bool
  16. }
  17. func NewForceContext(e *EventDistributor, w *DB, outbound chan PlayerEvent) *ExecutionContext {
  18. c := new(ExecutionContext)
  19. c.outbound = outbound
  20. c.eventDistributor = e
  21. c.db = w
  22. c.factory = NewObjectFactory(w)
  23. c.forceContext = true
  24. return c
  25. }
  26. func NewExecutionContext(actorID DBRef, e *EventDistributor, w *DB, outbound chan PlayerEvent) *ExecutionContext {
  27. c := new(ExecutionContext)
  28. actor, found := w.Fetch(actorID)
  29. if !found {
  30. return nil
  31. }
  32. c.actor = actor
  33. c.outbound = outbound
  34. c.eventDistributor = e
  35. c.db = w
  36. c.factory = NewObjectFactory(w)
  37. return c
  38. }
  39. func (c *ExecutionContext) StartInboundChannel() chan PlayerEvent {
  40. c.inbound = make(chan PlayerEvent)
  41. inboundBuffer := make(chan PlayerEvent)
  42. c.outbound = c.outbound
  43. go func() {
  44. //inbound event buffer to protect the event distributor from long running tasks
  45. // the alternative is to run each inbound event in a separate goroutine
  46. // but that has potential problems (ie, two emits arrive in order. the first one
  47. // requires an extra DB lookup to sort out context. now the second one ends up
  48. // sending its output event before the first, and the client sees things backwards
  49. // this isn't just an edge case, it happens quite frequently.
  50. // The alternative is to buffer inbound events, which is the safest, as it doesn't
  51. // impact the eventdistributor.
  52. queue := make([]*PlayerEvent, 0)
  53. running := true
  54. for running {
  55. if len(queue) == 0 {
  56. select {
  57. case newEvent, ok := <-c.inbound:
  58. if !ok {
  59. running = false
  60. break
  61. }
  62. queue = append(queue, &newEvent)
  63. }
  64. } else {
  65. event := queue[0]
  66. select {
  67. case newEvent, ok := <-c.inbound:
  68. if !ok {
  69. running = false
  70. break
  71. }
  72. queue = append(queue, &newEvent)
  73. case inboundBuffer <- *event:
  74. queue = queue[1:]
  75. }
  76. }
  77. }
  78. // closure of c.inbound is the signal from the event distributor that we need to die.
  79. // we then close inboundBuffer to tell the event goroutine to die
  80. fmt.Println("close(inboundBuffer)")
  81. close(inboundBuffer)
  82. }()
  83. go func() {
  84. for {
  85. event, ok := <-inboundBuffer
  86. if !ok {
  87. break
  88. }
  89. c.HandleEvent(event)
  90. }
  91. // and finally we tell the event distributor to delete us.
  92. fmt.Println("Sending EventTypeTeardownComplete")
  93. c.outbound <- PlayerEvent{src: c.actor.ID, dst: c.actor.ID, messageType: EventTypeTeardownComplete}
  94. }()
  95. return c.inbound
  96. }
  97. func (c *ExecutionContext) HandleEvent(m PlayerEvent) {
  98. inside, _ := c.db.GetParent(c.actor.ID)
  99. switch m.messageType {
  100. case EventTypeEmit:
  101. fallthrough
  102. case EventTypeOEmit:
  103. if m.dst == inside {
  104. c.output("%s", m.message)
  105. }
  106. case EventTypePEmit:
  107. c.output("%s", m.message)
  108. case EventTypeWall:
  109. speaker, found := c.db.Fetch(m.src)
  110. if !found {
  111. break
  112. }
  113. c.output("In the distance, you hear %s bellow out \"%s\"", speaker.Name, m.message)
  114. case EventTypePage:
  115. speaker, found := c.db.Fetch(m.src)
  116. if !found {
  117. break
  118. }
  119. c.output("%s pages you: \"%s\"", speaker.Name, m.message)
  120. case EventTypeSay:
  121. if m.dst == inside {
  122. speaker, found := c.db.Fetch(m.src)
  123. if !found {
  124. break
  125. }
  126. c.output("%s says \"%s\"", speaker.Name, m.message)
  127. }
  128. case EventTypePose:
  129. if m.dst == inside {
  130. if m.src == c.actor.ID {
  131. c.output("%s %s", c.actor.Name, m.message)
  132. } else {
  133. speaker, found := c.db.Fetch(m.src)
  134. if !found {
  135. break
  136. }
  137. c.output("%s %s", speaker.Name, m.message)
  138. }
  139. }
  140. case EventTypeForce:
  141. actor, found := c.db.Fetch(m.dst)
  142. if !found {
  143. break
  144. }
  145. c.actor = actor
  146. c.evaluateCommand(m)
  147. case EventTypeCommand:
  148. c.evaluateCommand(m)
  149. }
  150. }
  151. func (c *ExecutionContext) evaluateCommand(m PlayerEvent) {
  152. message := m.message
  153. c.actor.Refresh()
  154. switch {
  155. case message == "l":
  156. c.lookCmd("")
  157. case message == "look":
  158. c.lookCmd("")
  159. case strings.HasPrefix(message, "l "): // look at
  160. c.lookCmd(strings.TrimPrefix(message, "l "))
  161. case strings.HasPrefix(message, "look "): // look at
  162. c.lookCmd(strings.TrimPrefix(message, "look "))
  163. case strings.HasPrefix(message, "ex "):
  164. c.examineCmd(strings.TrimPrefix(message, "ex "))
  165. case strings.HasPrefix(message, "examine "):
  166. c.examineCmd(strings.TrimPrefix(message, "examine "))
  167. case strings.HasPrefix(message, "\""):
  168. c.sayCmd(strings.TrimPrefix(message, "\""))
  169. case strings.HasPrefix(message, "say "):
  170. c.sayCmd(strings.TrimPrefix(message, "say "))
  171. case strings.HasPrefix(message, ":"):
  172. c.poseCmd(strings.TrimPrefix(message, ":"))
  173. case strings.HasPrefix(message, "pose "):
  174. c.poseCmd(strings.TrimPrefix(message, "pose "))
  175. case message == "i":
  176. c.inventoryCmd()
  177. case message == "inventory":
  178. c.inventoryCmd()
  179. case strings.HasPrefix(message, "get "):
  180. c.getCmd(strings.TrimPrefix(message, "get "))
  181. case strings.HasPrefix(message, "drop "):
  182. c.dropCmd(strings.TrimPrefix(message, "drop "))
  183. case strings.HasPrefix(message, "enter "):
  184. c.enterCmd(strings.TrimPrefix(message, "enter "))
  185. case message == "leave":
  186. c.leaveCmd()
  187. case message == "quit":
  188. c.quitCmd(m.connectionID)
  189. case message == "WHO":
  190. c.whoCmd()
  191. case message == "HOWLONG":
  192. time.Sleep(5 * time.Second)
  193. case strings.HasPrefix(message, "@create "):
  194. c.createCmd(strings.TrimPrefix(message, "@create "))
  195. case strings.HasPrefix(message, "@dig "):
  196. c.digCmd(message)
  197. case strings.HasPrefix(message, "@open "):
  198. c.openCmd(message)
  199. case strings.HasPrefix(message, "@name "):
  200. c.nameCmd(message)
  201. case strings.HasPrefix(message, "@desc "):
  202. c.descCmd(message)
  203. case strings.HasPrefix(message, "@tel "):
  204. c.telCmd(strings.TrimPrefix(message, "@tel "))
  205. case strings.HasPrefix(message, "@dump "):
  206. c.dumpCmd(strings.TrimPrefix(message, "@dump "))
  207. case strings.HasPrefix(message, "@destroy "):
  208. c.destroyCmd(strings.TrimPrefix(message, "@destroy "))
  209. case strings.HasPrefix(message, "@force "):
  210. c.forceCmd(message)
  211. default:
  212. if !c.goCmd(message) {
  213. c.output("What?\n")
  214. }
  215. }
  216. }
  217. func (c *ExecutionContext) lookCmd(at string) {
  218. roomID, found := c.db.GetParent(c.actor.ID)
  219. room, found := c.db.Fetch(roomID)
  220. if !found {
  221. c.output("True Limbo (#NaN)\nThere's nothing to see here. You are inside an object that doesn't exist.")
  222. return
  223. }
  224. if len(at) > 0 {
  225. object, matchType := room.MatchLinkNames(at, c.actor.ID).ExactlyOne()
  226. switch matchType {
  227. case MatchOne:
  228. c.output("%s\n%s", object.DetailedName(), object.Description)
  229. case MatchNone:
  230. c.output("I don't see that here.")
  231. case MatchMany:
  232. c.output("I don't now which one you're trying to look at.")
  233. }
  234. } else {
  235. c.output("%s\n%s", room.DetailedName(), room.Description)
  236. lookLinks := func(linkType string, pretty string) {
  237. linknames := room.GetLinkNames(linkType, DBRefList{c.actor.ID})
  238. if len(linknames) > 0 {
  239. c.output("%s\n %s", pretty, strings.Join(linknames, "\n "))
  240. }
  241. }
  242. lookLinks("thing", "Things:")
  243. lookLinks("player", "Players:")
  244. exits := room.GetLinkNames("exit", nil)
  245. if len(exits) > 0 {
  246. c.output("Exits:")
  247. exitList := make([]string, 0)
  248. for _, e := range exits {
  249. aliases := strings.Split(e, ";")
  250. exitList = append(exitList, aliases[0])
  251. }
  252. c.output(strings.Join(exitList, " "))
  253. }
  254. }
  255. }
  256. func (c *ExecutionContext) objectName(id DBRef) string {
  257. o, found := c.db.Fetch(id)
  258. if found {
  259. return o.DetailedName()
  260. } else {
  261. return fmt.Sprintf("MISSING OBJECT (#%d)", id)
  262. }
  263. }
  264. func (c *ExecutionContext) examineCmd(at string) {
  265. roomID, found := c.db.GetParent(c.actor.ID)
  266. room, found := c.db.Fetch(roomID)
  267. if !found {
  268. return
  269. }
  270. object, matchType := room.MatchLinkNames(at, c.actor.ID).ExactlyOne()
  271. switch matchType {
  272. case MatchOne:
  273. objectParentID, _ := c.db.GetParent(object.ID)
  274. c.output("%s", object.DetailedName())
  275. c.output("ID: %d", object.ID)
  276. c.output("Type: %s", object.Type)
  277. c.output("@name: %s", object.Name)
  278. c.output("@desc: %s", object.Description)
  279. c.output("Inside: %s", c.objectName(objectParentID))
  280. c.output("Next: %s", c.objectName(object.Next))
  281. c.output("Owner: %s", c.objectName(object.Owner))
  282. inventory := object.GetLinkNames("*", nil)
  283. if len(inventory) > 0 {
  284. c.output("Contents:\n %s", strings.Join(inventory, "\n "))
  285. }
  286. case MatchNone:
  287. c.output("I don't see that here.")
  288. case MatchMany:
  289. c.output("I don't know which one you're trying to examine.")
  290. }
  291. }
  292. func (c *ExecutionContext) forceCmd(input string) {
  293. r, _ := regexp.Compile(`^@force\pZ+([^=]*[^=\pZ]{1})\pZ*=\pZ*(.*)\pZ*$`)
  294. params := r.FindStringSubmatch(input)
  295. if params == nil {
  296. return
  297. }
  298. objectName, command := params[1], params[2]
  299. roomID, found := c.db.GetParent(c.actor.ID)
  300. room, found := c.db.Fetch(roomID)
  301. if !found {
  302. return
  303. }
  304. objectID, err := NewDBRefFromHashRef(objectName)
  305. wizard := false
  306. if err == nil {
  307. object, found := c.db.Fetch(objectID)
  308. if !found {
  309. c.output("I can't force what doesn't exist.")
  310. }
  311. if object.Type == "thing" || (object.Type == "player" && wizard) {
  312. c.outbound <- PlayerEvent{src: c.actor.ID, dst: object.ID, message: command, messageType: EventTypeForce}
  313. } else {
  314. c.output("Some things just can't be forced.")
  315. }
  316. } else {
  317. object, matchType := room.MatchLinkNames(objectName, c.actor.ID).ExactlyOne()
  318. switch matchType {
  319. case MatchOne:
  320. if object.Type == "thing" || (object.Type == "player" && wizard) {
  321. c.outbound <- PlayerEvent{src: c.actor.ID, dst: object.ID, message: command, messageType: EventTypeForce}
  322. } else {
  323. c.output("Some things just can't be forced.")
  324. }
  325. case MatchNone:
  326. c.output("I don't see that here.")
  327. case MatchMany:
  328. c.output("I don't know which one you're trying to examine.")
  329. }
  330. }
  331. }
  332. func (c *ExecutionContext) sayCmd(message string) {
  333. inside, _ := c.db.GetParent(c.actor.ID)
  334. c.output("You say \"%s\"", message)
  335. c.outbound <- PlayerEvent{src: c.actor.ID, dst: inside, message: message, messageType: EventTypeSay}
  336. }
  337. func (c *ExecutionContext) poseCmd(message string) {
  338. inside, _ := c.db.GetParent(c.actor.ID)
  339. c.outbound <- PlayerEvent{src: c.actor.ID, dst: inside, message: message, messageType: EventTypePose}
  340. }
  341. func (c *ExecutionContext) inventoryCmd() {
  342. inventory := c.actor.GetLinkNames("*", nil)
  343. if len(inventory) > 0 {
  344. c.output("Inventory:\n %s", strings.Join(inventory, "\n "))
  345. } else {
  346. c.output("You're not carrying anything.")
  347. }
  348. }
  349. func (c *ExecutionContext) getCmd(message string) {
  350. roomID, found := c.db.GetParent(c.actor.ID)
  351. room, found := c.db.Fetch(roomID)
  352. if !found {
  353. return
  354. }
  355. object, matchType := room.MatchLinkNames(message, c.actor.ID).ExactlyOne()
  356. switch matchType {
  357. case MatchOne:
  358. if object.ID == c.actor.ID {
  359. c.output("You can't pick yourself up.")
  360. return
  361. }
  362. err := c.actor.Contains(&object)
  363. if err != nil {
  364. return
  365. }
  366. //c.actor.Refresh()
  367. c.output("You pick up %s.", object.Name)
  368. c.pemit(object.ID, "%s picked you up.", c.actor.Name)
  369. c.oemit(room.ID, "%s picks up %s.", c.actor.Name, object.Name)
  370. case MatchNone:
  371. c.output("I don't see that here.")
  372. case MatchMany:
  373. c.output("I don't know which one.")
  374. }
  375. }
  376. func (c *ExecutionContext) dropCmd(message string) {
  377. roomID, found := c.db.GetParent(c.actor.ID)
  378. room, found := c.db.Fetch(roomID)
  379. if !found {
  380. return
  381. }
  382. object, matchType := c.actor.MatchLinkNames(message, c.actor.ID).ExactlyOne()
  383. switch matchType {
  384. case MatchOne:
  385. err := room.Contains(&object)
  386. if err != nil {
  387. return
  388. }
  389. inside, _ := c.db.GetParent(c.actor.ID)
  390. c.output("You drop %s.", object.Name)
  391. c.pemit(object.ID, "%s drops you.", c.actor.Name)
  392. c.oemit(inside, "%s drops %s.", c.actor.Name, object.Name)
  393. case MatchNone:
  394. c.output("You're not carrying that.")
  395. case MatchMany:
  396. c.output("I don't now which one.")
  397. }
  398. }
  399. func (c *ExecutionContext) enterCmd(message string) {
  400. roomID, found := c.db.GetParent(c.actor.ID)
  401. room, found := c.db.Fetch(roomID)
  402. if !found {
  403. return
  404. }
  405. object, matchType := room.MatchLinkNames(message, c.actor.ID).ExactlyOne()
  406. switch matchType {
  407. case MatchOne:
  408. if object.ID == c.actor.ID {
  409. c.output("Entering yourself would be a bad idea.")
  410. return
  411. }
  412. err := object.Contains(&c.actor)
  413. if err != nil {
  414. return
  415. }
  416. c.output("You climb into %s.", object.Name)
  417. c.oemit(room.ID, "%s climbs into %s.", c.actor.Name, object.Name)
  418. c.oemit(object.ID, "%s squeezes into %s with you.", c.actor.Name, object.Name)
  419. case MatchNone:
  420. c.output("I don't see that here.")
  421. case MatchMany:
  422. c.output("I don't now which one.")
  423. }
  424. }
  425. func (c *ExecutionContext) leaveCmd() {
  426. inside, _ := c.db.GetParent(c.actor.ID)
  427. object, found := c.db.Fetch(inside)
  428. if !found {
  429. return
  430. }
  431. objectInside, _ := c.db.GetParent(inside)
  432. if objectInside == 0 { // probably trying to 'leave' a room
  433. c.output("You can't leave here.")
  434. return
  435. }
  436. room, found := c.db.Fetch(objectInside)
  437. if !found {
  438. return
  439. }
  440. err := room.Contains(&c.actor)
  441. if err != nil {
  442. return
  443. }
  444. //c.actor.Refresh()
  445. c.output("You climb out of %s.", object.Name)
  446. c.oemit(object.ID, "%s climbs out of %s.", c.actor.Name, object.Name)
  447. c.oemit(room.ID, "%s climbs out of %s.", c.actor.Name, object.Name)
  448. }
  449. func (c *ExecutionContext) quitCmd(connectionID int) {
  450. c.output("So long, it's been good to know yah.")
  451. c.outbound <- PlayerEvent{src: c.actor.ID, dst: c.actor.ID, messageType: EventTypeQuit, connectionID: connectionID}
  452. }
  453. func (c *ExecutionContext) whoCmd() {
  454. // onlinePlayers := c.eventDistributor.OnlinePlayers()
  455. c.output("Currently Online:\n")
  456. //for _, ref := range onlinePlayers {
  457. // c.output("%s\n", c.db.GetName(ref))
  458. //}
  459. }
  460. func (c *ExecutionContext) createCmd(message string) {
  461. roomID, found := c.db.GetParent(c.actor.ID)
  462. room, found := c.db.Fetch(roomID)
  463. if !found {
  464. return
  465. }
  466. o := c.factory.NewThing()
  467. o.Name = strings.TrimSpace(message)
  468. o.Owner = c.actor.ID
  469. o.Commit()
  470. err := room.Contains(&o)
  471. if err != nil {
  472. return
  473. }
  474. c.oemit(room.ID, "A %s appears out of the ether.", o.Name)
  475. c.output("%s Created.", o.DetailedName())
  476. }
  477. func (c *ExecutionContext) openCmd(input string) {
  478. // @open <in1;in2;in3;etc>=#<room>,<out1;out2;out3;etc>
  479. r, _ := regexp.Compile(`^@open\pZ+([^=]*[^=\pZ]+)\pZ*=#([0-9]+)(?:\pZ*,\pZ*([^,]*[^,\pZ]+)\pZ*)?`)
  480. params := r.FindStringSubmatch(input)
  481. if params == nil {
  482. return
  483. }
  484. inExit, roomIDStr, outExit := params[1], params[2], params[3]
  485. if len(inExit) == 0 || len(roomIDStr) == 0 {
  486. c.output("Bad command or file name.")
  487. return
  488. }
  489. targetID, _ := NewDBRefFromString(roomIDStr) // this will never fail, the regexp guarantees that
  490. targetRoom, found := c.db.Fetch(targetID)
  491. if !found {
  492. c.output("Target not found.")
  493. return
  494. }
  495. roomID, found := c.db.GetParent(c.actor.ID)
  496. room, found := c.db.Fetch(roomID)
  497. if !found {
  498. return
  499. }
  500. toExit := c.factory.NewExit(inExit, targetRoom.ID, c.actor.ID)
  501. toExit.Commit()
  502. err := room.Contains(&toExit)
  503. if err != nil {
  504. return
  505. }
  506. c.output("%s Created.", toExit.DetailedName())
  507. if len(outExit) > 0 {
  508. fromExit := c.factory.NewExit(outExit, room.ID, c.actor.ID)
  509. fromExit.Commit()
  510. err = targetRoom.Contains(&fromExit)
  511. if err != nil {
  512. return
  513. }
  514. c.output("%s Created.", fromExit.DetailedName())
  515. }
  516. }
  517. func (c *ExecutionContext) digCmd(input string) {
  518. // @dig <Room name>=<in1;in2;in3;etc>,<out1;out2;out3;etc>
  519. //@dig foo bar = <F>oo;foo;f,<B>ack;back;b
  520. r, _ := regexp.Compile(`^@dig\pZ+([^=]*[^=\pZ]+)(\pZ*=\pZ*(?:([^,]*[^,\pZ]+)\pZ*)?(?:\pZ*,\pZ*([^,]*[^,\pZ]+)\pZ*)?)?`)
  521. params := r.FindStringSubmatch(input)
  522. if params == nil {
  523. return
  524. }
  525. roomName, inExit, outExit := params[1], params[2], params[3]
  526. if len(roomName) == 0 {
  527. c.output("Rooms can't not have names.")
  528. return
  529. }
  530. newRoom := c.factory.NewRoom()
  531. newRoom.Name = roomName
  532. newRoom.Owner = c.actor.ID
  533. newRoom.Commit()
  534. c.output("%s Created.", newRoom.DetailedName())
  535. if len(inExit) > 0 || len(outExit) > 0 {
  536. roomID, found := c.db.GetParent(c.actor.ID)
  537. room, found := c.db.Fetch(roomID)
  538. if !found {
  539. return
  540. }
  541. if len(inExit) > 0 {
  542. toExit := c.factory.NewExit(inExit, newRoom.ID, c.actor.ID)
  543. toExit.Commit()
  544. err := room.Contains(&toExit)
  545. if err != nil {
  546. return
  547. }
  548. c.output("%s Created.", toExit.DetailedName())
  549. }
  550. if len(outExit) > 0 {
  551. fromExit := c.factory.NewExit(outExit, room.ID, c.actor.ID)
  552. fromExit.Commit()
  553. err := newRoom.Contains(&fromExit)
  554. if err != nil {
  555. return
  556. }
  557. c.output("%s Created.", fromExit.DetailedName())
  558. }
  559. }
  560. }
  561. func (c *ExecutionContext) nameCmd(input string) {
  562. r, _ := regexp.Compile(`^@name\pZ+([^=]*[^=\pZ]{1})\pZ*=\pZ*(.*)\pZ*$`)
  563. params := r.FindStringSubmatch(input)
  564. if params == nil {
  565. return
  566. }
  567. objectName, name := params[1], params[2]
  568. roomID, found := c.db.GetParent(c.actor.ID)
  569. room, found := c.db.Fetch(roomID)
  570. if !found {
  571. return
  572. }
  573. candidate, matchType := room.MatchLinkNames(objectName, c.actor.ID).ExactlyOne()
  574. switch matchType {
  575. case MatchOne:
  576. candidate.Name = name
  577. candidate.Commit()
  578. c.output("Name set.")
  579. //c.actor.Refresh()
  580. case MatchNone:
  581. c.output("I don't see that here.")
  582. case MatchMany:
  583. c.output("I don't now which one.")
  584. }
  585. }
  586. func (c *ExecutionContext) descCmd(input string) {
  587. r, _ := regexp.Compile(`^@desc\pZ+([^=]*[^=\pZ]{1})\pZ*=\pZ*(.*)\pZ*$`)
  588. params := r.FindStringSubmatch(input)
  589. if params == nil {
  590. return
  591. }
  592. objectName, description := params[1], params[2]
  593. roomID, found := c.db.GetParent(c.actor.ID)
  594. room, found := c.db.Fetch(roomID)
  595. if !found {
  596. return
  597. }
  598. var editObject *Object
  599. switch objectName {
  600. case "here":
  601. editObject = &room
  602. case "me":
  603. editObject = &c.actor
  604. default:
  605. candidate, matchType := room.MatchLinkNames(objectName, c.actor.ID).ExactlyOne()
  606. switch matchType {
  607. case MatchOne:
  608. editObject = &candidate
  609. case MatchNone:
  610. c.output("I don't see that here.")
  611. return
  612. case MatchMany:
  613. c.output("I don't now which one.")
  614. return
  615. }
  616. }
  617. editObject.Description = description
  618. editObject.Commit()
  619. //c.actor.Refresh()
  620. c.output("Description set.")
  621. }
  622. func (c *ExecutionContext) telCmd(destStr string) {
  623. dest, err := NewDBRefFromHashRef(destStr)
  624. if err != nil {
  625. c.output("That doesn't look like a DBRef.")
  626. return
  627. }
  628. newRoom, found := c.db.Fetch(dest)
  629. if !found {
  630. c.output("That doesn't exist.")
  631. return
  632. }
  633. c.output("You feel an intense wooshing sensation.")
  634. err = newRoom.Contains(&c.actor)
  635. if err != nil {
  636. return
  637. }
  638. c.actor.Refresh()
  639. c.lookCmd("")
  640. }
  641. func (c *ExecutionContext) dumpCmd(refStr string) {
  642. ref, err := NewDBRefFromHashRef(refStr)
  643. if err != nil {
  644. c.output("That doesn't look like a DBRef.")
  645. return
  646. }
  647. obj, found := c.db.Fetch(ref)
  648. if !found {
  649. c.output("That doesn't exist.")
  650. return
  651. }
  652. c.output("%s", c.db.DumpObject(obj.ID))
  653. }
  654. func (c *ExecutionContext) destroyCmd(message string) {
  655. roomID, found := c.db.GetParent(c.actor.ID)
  656. room, found := c.db.Fetch(roomID)
  657. if !found {
  658. return
  659. }
  660. object, matchType := room.MatchLinkNames(message, c.actor.ID).ExactlyOne()
  661. switch matchType {
  662. case MatchOne:
  663. if object.ID == c.actor.ID {
  664. c.output("There are alternatives to suicide.")
  665. return
  666. }
  667. if object.Type == "player" {
  668. c.output("I didn't think homicide was your thing.")
  669. return
  670. }
  671. name := object.DetailedName()
  672. err := object.Delete()
  673. if err == nil {
  674. //c.actor.Refresh()
  675. c.output("%s vanishes into thin air.", name)
  676. }
  677. case MatchNone:
  678. c.output("I don't see that here.")
  679. case MatchMany:
  680. c.output("I don't know which one.")
  681. }
  682. }
  683. func (c *ExecutionContext) goCmd(dir string) bool {
  684. roomID, found := c.db.GetParent(c.actor.ID)
  685. room, found := c.db.Fetch(roomID)
  686. if !found {
  687. return false
  688. }
  689. exit, matchType := room.MatchExitNames(dir).ExactlyOne()
  690. switch matchType {
  691. case MatchOne:
  692. if exit.Next.Valid() {
  693. newRoom, found := c.db.Fetch(exit.Next)
  694. if !found {
  695. c.output("That exit appears to be broken!")
  696. return true
  697. }
  698. err := newRoom.Contains(&c.actor)
  699. if err != nil {
  700. return false
  701. }
  702. //c.actor.Refresh()
  703. c.output("You head towards %s.", newRoom.Name)
  704. c.oemit(room.ID, "%s leaves the room.", c.actor.Name)
  705. c.oemit(newRoom.ID, "%s enters the room.", c.actor.Name)
  706. return true
  707. }
  708. case MatchNone:
  709. return false
  710. case MatchMany:
  711. c.output("Ambiguous exit names are ambiguous.")
  712. return true
  713. }
  714. return false
  715. }
  716. func (c *ExecutionContext) oemit(audience DBRef, format string, a ...interface{}) {
  717. message := fmt.Sprintf(format, a...)
  718. c.outbound <- PlayerEvent{src: c.actor.ID, dst: audience, message: message, messageType: EventTypeOEmit}
  719. }
  720. func (c *ExecutionContext) output(format string, a ...interface{}) {
  721. message := fmt.Sprintf(format, a...)
  722. if !c.forceContext {
  723. c.outbound <- PlayerEvent{src: c.actor.ID, dst: c.actor.ID, message: message, messageType: EventTypeOutput}
  724. }
  725. }
  726. func (c *ExecutionContext) pemit(target DBRef, format string, a ...interface{}) {
  727. message := fmt.Sprintf(format, a...)
  728. c.outbound <- PlayerEvent{src: c.actor.ID, dst: target, message: message, messageType: EventTypePEmit}
  729. }
  730. func (c *ExecutionContext) emit(audience DBRef, format string, a ...interface{}) {
  731. message := fmt.Sprintf(format, a...)
  732. c.outbound <- PlayerEvent{src: c.actor.ID, dst: audience, message: message, messageType: EventTypeEmit}
  733. }