ChatdServerClientExample: Difference between revisions
Jump to navigation
Jump to search
Content deleted Content added
No edit summary |
imported>Hendrik Brummermann Redirected page to Marauroa Chat Tutorial |
||
| (34 intermediate revisions by 4 users not shown) | |||
| Line 1: | Line 1: | ||
#REDIRECT [[Marauroa Chat Tutorial]] |
|||
A very simple example for you, the lazy reader, who can't be bothered to read the manual!<br> |
|||
But note, this example is by no way a substitute of HowToWriteGamesUsingArianne and it is only intended for readers that want a light introduction to Arianne. |
|||
=Server= |
|||
First we create the server class using python. |
|||
<pre> |
|||
import marauroa.game.python.PythonRP |
|||
class ChatServer(marauroa.game.python.PythonRP): |
|||
def __init__(self, zone): |
|||
self._zone=zone |
|||
self._removeAttributes=[] |
|||
def execute(self, id, action): |
|||
result=0 |
|||
player=self._zone.get(id) |
|||
action_code=action.get("type") |
|||
if action_code='chat': |
|||
player.put('text',action.get('text')) |
|||
self._zone.modify(player) |
|||
self._removeAttributes.append(player) |
|||
result=1 |
|||
return result |
|||
def nextTurn(self): |
|||
for player in self._removeAttributes: |
|||
if player.has('text'): |
|||
player.remove('text') |
|||
self._zone.modify(player) |
|||
def onInit(self, object): |
|||
self._zone.add(object) |
|||
return 1 |
|||
def onExit(self, objectid): |
|||
self._zone.remove(objectid) |
|||
return 1 |
|||
def onTimeout(self, objectid): |
|||
return onExit(self,objectid) |
|||
</pre> |
|||
Ok, most of it is just trivial stuff. The core code is at execute and nextTurn.<br> |
|||
The execute method is the one called to execute the actions the client sends and it is really simple, it adds the messages content as a player attribute, and the trick thing is that is add the player a list so that it can be deleted the attribute in the next turn. |
|||
The nextTurn just delete the attributes that now are useless. |
|||
=Client= |
|||
The client is a bit more complex. We need to make it login and choose a character. We will use a curses wrapper for python. |
|||
'''TODO:''' Improve it |
|||
<pre> |
|||
import pyarianne |
|||
import curses |
|||
import os |
|||
import time |
|||
import signal |
|||
import sys |
|||
def sendMessage(lines): |
|||
text = "" |
|||
for i in lines: |
|||
text = text + i + "\n" |
|||
action=pyarianne.RPAction() |
|||
action.put("type","chat") |
|||
action.put("content",text) |
|||
pyarianne.send(action) |
|||
def paintStatusArea(text): |
|||
statusArea.clear() |
|||
statusArea.border() |
|||
statusArea.addstr(1,1,text) |
|||
statusArea.refresh() |
|||
def paintTextArea(history_lines): |
|||
textArea.clear() |
|||
textArea.border() |
|||
textArea.addstr(0,3," The first marauroa-python-curses-chat client ") |
|||
row=1 |
|||
for line_entry in history_lines: |
|||
name = line_entry['name'] |
|||
text = line_entry['text'] |
|||
name = name.rjust(16)+": " |
|||
textArea.addstr(row,1,name,curses.color_pair(1)) |
|||
textArea.addstr(text,curses.color_pair(2)) |
|||
row=row+1 |
|||
textArea.refresh() |
|||
def paintInputArea(text): |
|||
inputArea.clear() |
|||
inputArea.border() |
|||
inputArea.addstr(1,1,">"+text) |
|||
inputArea.refresh() |
|||
def repaintInputArea(): |
|||
global text |
|||
paintInputArea(text) |
|||
def dostuffonCallback(): |
|||
if False: |
|||
winmain.addstr(0,0,"Calling from Python!") |
|||
def printChatMessage(world): |
|||
global history_lines |
|||
if True: |
|||
for i in world.objects: |
|||
if world.objects[i].get("type") == "character": |
|||
name = world.objects[i].get("name") |
|||
if world.objects[i].has("?text"): |
|||
text = world.objects[i].get("?text") |
|||
text_lines = text.split("\n") |
|||
for line in text_lines: |
|||
if line != "": |
|||
history_lines.append({'name': name,'text': line}) |
|||
#if overflow - remove first element |
|||
while len(history_lines) > 18: |
|||
history_lines.pop(0) |
|||
paintTextArea(history_lines) |
|||
repaintInputArea() |
|||
def initCurses(): |
|||
stdscr = curses.initscr() |
|||
curses.noecho() |
|||
curses.cbreak() |
|||
stdscr.keypad(True) |
|||
stdscr.nodelay(True) |
|||
if curses.has_colors(): |
|||
curses.start_color() |
|||
curses.init_pair(1, curses.COLOR_BLUE, curses.COLOR_BLACK); |
|||
curses.init_pair(2, curses.COLOR_GREEN, curses.COLOR_BLACK); |
|||
curses.init_pair(3, curses.COLOR_YELLOW, curses.COLOR_BLACK); |
|||
curses.init_pair(4, curses.COLOR_RED, curses.COLOR_BLACK); |
|||
curses.init_pair(5, curses.COLOR_CYAN, curses.COLOR_BLACK); |
|||
curses.init_pair(6, curses.COLOR_MAGENTA,curses.COLOR_BLACK); |
|||
curses.init_pair(7, curses.COLOR_WHITE, curses.COLOR_BLACK); |
|||
return stdscr |
|||
def uninitCurses(sign,arg2): |
|||
signal.signal(sign, signal.SIG_IGN) |
|||
try: |
|||
curses.nocbreak() |
|||
stdscr.keypad(0) |
|||
stdscr.nodelay(0) |
|||
curses.echo() |
|||
curses.endwin() |
|||
print "Exiting by signal "+ str(sign) |
|||
except err: |
|||
print "Exception: " +str(err) |
|||
sys.exit(0) |
|||
stdscr = initCurses() |
|||
#register singal handler to be able to restore the console |
|||
signal.signal(signal.SIGINT, uninitCurses) |
|||
signal.signal(signal.SIGTERM, uninitCurses) |
|||
begin_x = 0 ; begin_y = 0 |
|||
height = 20 ; width = 100 |
|||
textArea = curses.newwin(height, width, begin_y, begin_x) |
|||
begin_x = 0 ; begin_y = 20 |
|||
height = 3 ; width = 100 |
|||
inputArea = curses.newwin(height, width, begin_y, begin_x) |
|||
inputArea.keypad(True) |
|||
inputArea.nodelay(True) |
|||
begin_x = 0 ; begin_y = 23 |
|||
height = 3 ; width = 100 |
|||
statusArea = curses.newwin(height, width, begin_y, begin_x) |
|||
world=pyarianne.World() |
|||
perceptionHandler=pyarianne.PerceptionHandler() |
|||
pyarianne.setIdleMethod(dostuffonCallback) |
|||
pyarianne.connectToArianne("marauroa.ath.cx",3214) |
|||
paintStatusArea("Connecting to server...") |
|||
text = "" |
|||
history_lines = [] |
|||
if pyarianne.login("root777","root777"): |
|||
chars=pyarianne.availableCharacters() |
|||
paintStatusArea("Logged in, choosing character "+chars[0]+"...") |
|||
if pyarianne.chooseCharacter(chars[0]): |
|||
paintStatusArea("Choosed character "+chars[0]) |
|||
exit = False |
|||
repaintInputArea() |
|||
while True: |
|||
time.sleep(0.2) |
|||
if pyarianne.hasPerception(): |
|||
perception=pyarianne.getPerception() |
|||
perceptionHandler.applyPerception(perception, world) |
|||
printChatMessage(world) |
|||
ch = inputArea.getch() |
|||
if ch != curses.ERR : |
|||
if ch == 10 or ch == curses.KEY_ENTER: #enter |
|||
if text == "/quit": |
|||
break |
|||
if text != "": |
|||
sendMessage([text]) |
|||
text = "" |
|||
else: |
|||
text = text + str(chr(ch)) |
|||
repaintInputArea() |
|||
pyarianne.logout() |
|||
else: |
|||
paintStatusArea("CAN'T CHOOSE: "+pyarianne.errorReason()) |
|||
else: |
|||
paintStatusArea("CAN'T LOGIN: "+pyarianne.errorReason()) |
|||
paintStatusArea("Finishing pyclient") |
|||
uninitCurses(1,2) |
|||
</pre> |
|||
And here you can see how it looks: |
|||
http://tribus.dyndns.org/~keiner/cursed-chat-client.png |
|||