Commit ed944f14 authored by Alvin Natawiguna's avatar Alvin Natawiguna
Browse files

More functions implemented. Not tested though... :v

parent 669c2ee8
from abc import abstractmethod, ABCMeta
import json
import socket
from game.game import Game, GameMap
from game.player import Player
from game.map import Map
from game.item import Item
class Command(object):
......@@ -11,6 +13,7 @@ class Command(object):
Abstract base class for commands
"""
METHOD_JOIN = "join"
METHOD_SERVERSTATUS = "serverStatus"
METHOD_SIGNUP = "signup"
METHOD_LOGIN = "login"
......@@ -30,6 +33,7 @@ class Command(object):
def __init__(self):
super().__init__()
self.__error = None
"""
......@@ -37,9 +41,18 @@ class Command(object):
"""
@abstractmethod
def execute(self):
pass
raise NotImplementedError("You need to implement the method for your Command class")
def getStatus(self):
"""
Gets the status of the command's execution
Any error should be assigned to the self.__error variable.
If the self.__error object is a str, fail status will be returned
else, error status will be returned
returns dict object
"""
if not self.__error:
return {'status': 'ok'}
else:
......@@ -49,98 +62,185 @@ class Command(object):
return {'status': 'error'}
class CommandFactory(object):
def __init__(self, jsonObject):
def __init__(self, **jsonObject):
super().__init__()
self.__json = jsonObject
self.game = Game.getInstance()
def getCommand(self):
method = self.__json["method"]
if method == Command.METHOD_SERVERSTATUS:
if method == Command.METHOD_JOIN:
if 'ip' in self.__json and 'port' in self.__json:
return JoinCommand(self.__json['ip'], self.__json['port'])
else:
return JoinCommand()
elif method == Command.METHOD_SERVERSTATUS:
return ServerStatusCommand(self.__json['server'])
elif method == Command.METHOD_SIGNUP:
return SignupCommand(self.__json["username"], self.__json["password"])
return SignupCommand(self.game, self.__json["username"], self.__json["password"])
elif method == Command.METHOD_LOGIN:
return LoginCommand(self.__json["username"], self.__json["password"])
return LoginCommand(self.game, self.__json["username"], self.__json["password"])
elif method == Command.METHOD_INVENTORY:
return InventoryQueryCommand(self.__json["token"])
return InventoryQueryCommand(self.game, self.__json["token"])
elif method == Command.METHOD_MIXITEM:
return MixItemCommand(self.__json["token"], self.__json["item1"], self.__json["item2"])
return MixItemCommand(self.game, self.__json["token"], self.__json["item1"], self.__json["item2"])
elif method == Command.METHOD_MAP:
return MapQueryCommand(self.__json["token"])
return MapQueryCommand(self.game, self.__json["token"])
elif method == Command.METHOD_MOVE:
return MoveCommand(self.__json["token"], self.__json["x"], self.__json["y"])
return MoveCommand(self.game, self.__json["token"], self.__json["x"], self.__json["y"])
elif method == Command.METHOD_FIELD:
return GetItemFromFieldCommand(self.__json["token"])
return GetItemFromFieldCommand(self.game, self.__json["token"])
elif method == Command.METHOD_OFFER:
return MakeItemOfferCommand(self.__json["token"],
return MakeItemOfferCommand(self.game,
self.__json["token"],
self.__json["offered_item"],
self.__json["n1"],
self.__json["demanded_item"],
self.__json["n2"])
elif method == Command.METHOD_TRADEBOX:
return TradeboxQueryCommand(self.__json["token"])
return TradeboxQueryCommand(self.game, self.__json["token"])
elif method == Command.METHOD_SENDFIND:
return SendFindCommand(self.__json["token"], self.__json["item"])
return SendFindCommand(self.game, self.__json["token"], self.__json["item"])
elif method == Command.METHOD_FINDOFFER:
return FindOfferCommand(self.__json["item"])
return FindOfferCommand(self.__json["item"], self.__json["ip"], self.__json["port"])
elif method == Command.METHOD_SENDACCEPT:
return SendAcceptCommand(self.__json["token"], self.__json["offer_token"])
return SendAcceptCommand(self.game, self.__json["token"], self.__json["offer_token"])
elif method == Command.METHOD_ACCEPT:
return AcceptItemOfferCommand(self.__json["offer_token"])
return AcceptItemOfferCommand(self.__json["offer_token"], self.__json["ip"], self.__json["port"])
elif method == Command.METHOD_FETCHITEM:
return FetchOfferedItemCommand(self.__json["token"], self.__json["offer_token"])
return FetchOfferedItemCommand(self.game, self.__json["token"], self.__json["offer_token"])
elif method == Command.METHOD_CANCELOFFER:
return CancelItemOfferCommand(self.__json["token"], self.__json["offer_token"])
return CancelItemOfferCommand(self.game, self.__json["token"], self.__json["offer_token"])
else:
raise ValueError("Unknown method: {}".format(method))
# SERVER COMMANDS #
class JoinCommand(Command):
DEFAULT_TRACKER_IP, DEFAULT_TRACKER_PORT = '167.205.32.46', 8000
def __init__(self, ip = JoinCommand.DEFAULT_TRACKER_IP, port = JoinCommand.DEFAULT_TRACKER_PORT):
super().__init__()
self.ip = ip
self.port = port
self.result = None
def execute(self):
sock = socket.socket()
try:
sock.connect((self.ip, self.port))
sock.sendall(json.dumps({
'method': Command.METHOD_JOIN,
'ip': self.ip,
'port': self.port
}))
"""
This assumes that the server is going to send some small data.
Maybe in the future this needs to be revised, to handle arbitary-sized data.
"""
data = sock.recv(4096, 'utf-8')
if data:
self.result = json.loads(data)
else:
self.__error = True
except Exception, e:
self.__error = str(e)
finally:
sock.close()
def getStatus(self):
if self.result:
return self.result
else:
if not self.__error:
self.__error = True
super().getStatus()
class ServerStatusCommand(Command):
DB_COLLECTION_SERVER = 'activeServers'
def __init__(self, serverList):
super().__init__()
self.__servers = serverList
self.servers = serverList
def execute(self):
try:
for server in servers:
# TODO: put the data into the db
print ("{}{}".format(server['ip'], server['port']))
with pymongo.MongoClient().get_database(Game.DB_NAME) as db:
collection = db.get_collection(ServerStatusCommand.DB_COLLECTION_SERVER)
for server in enumerate(self.servers):
collection.update_one({'ip': server['ip']}, {'$set': {'port': server['port']} })
except Exception:
self.__error = True
class SignupCommand(Command):
def __init__(self, username, password):
def __init__(self, game, username, password):
super().__init__()
self.game = game
self.username = username
self.password = password
def execute(self):
pass
try:
game.playerSignup(self.username, self.password)
with pymongo.MongoClient().get_database(Game.DB_NAME) as db:
db.users.insert({
Player.KEY_USERNAME: self.username,
Player.KEY_PASSWORD: bcrypt.hashpw(self.password, bcrypt.gensalt()),
Player.KEY_ITEMS: [],
Player.KEY_CURRENTLOCATION: {
'x': 0,
'y': 0
},
Player.KEY_OFFERS: []
})
except Exception, e:
self.__error = str(e)
class LoginCommand(Command):
def __init__(self, username, password):
def __init__(self, game, username, password):
super().__init__()
self.game = game
self.username = username
self.password = password
self.player = None
self.token = None
def execute(self):
# TODO: find the player in the Game object, and generate the apropriate token
pass
try:
self.token = game.playerLogin(self.username, self.password)
# should not fail. Not yet tested though .__.
self.player = game.getPlayer(token = self.token)
if not self.player:
self.__error = True
except Exception, e:
self.__error = str(e)
def getStatus(self):
if not self.error and self.player:
if not self.error and self.token:
return {
'status': 'ok',
'token': self.__player.__id,
'x': self.__player.currentLocation.x,
'y': self.__player.currentLocation.y,
'token': self.token,
'x': self.player.currentLocation.x,
'y': self.player.currentLocation.y,
'time': int(time.time())
}
else:
......@@ -154,14 +254,20 @@ class InventoryQueryCommand(Command):
docstring for InventoryQueryCommand
"""
def __init__(self, token):
def __init__(self, game, token):
super().__init__()
self.game = game
self.token = token
self.inventory = []
def execute(self):
# TODO: get the inventory from the game class
pass
player = game.getPlayer(token = self.token)
if not player:
self.__error = True
else:
self.inventory = player.getInventory()
def getStatus(self):
if not self.error and self.inventory:
......@@ -177,9 +283,10 @@ class InventoryQueryCommand(Command):
class MixItemCommand(Command):
def __init__(self, token, item1_id, item2_id):
def __init__(self, game, token, item1_id, item2_id):
super().__init__()
self.game = game
self.token = token
self.item1 = item1_id
self.item2 = item2_id
......@@ -187,8 +294,12 @@ class MixItemCommand(Command):
self.result = None
def execute(self):
# TODO: mix the items
pass
player = game.getPlayer(token = self.token)
if player:
else:
self.__error = True
def getStatus(self):
if self.result:
......@@ -204,15 +315,18 @@ class MixItemCommand(Command):
class MapQueryCommand(Command):
def __init__(self, token):
def __init__(self, game, token):
super().__init__()
self.game = game
self.token = token
self.map = None
def execute(self):
# TODO: get the map info
pass
if player.getPlayer(token = self.token):
self.map = game.map
else:
self.__error = True
def getStatus(self):
if self.map:
......@@ -230,16 +344,25 @@ class MapQueryCommand(Command):
class MoveCommand(Command):
def __init__(self, token, x, y):
def __init__(self, game, token, x, y):
super().__init__()
self.game = game
self.token = token
self.x = x
self.y = y
def execute(self):
# TODO: move the player
pass
player = self.game.getPlayer(token = self.token)
if not player:
self.__error = True
else:
try:
player.moveTo(x = x, y = y)
# TODO: update the player's position in the db
except Exception, e:
self.__error = str(e)
def getStatus(self):
if not self.__error:
......@@ -253,15 +376,25 @@ class MoveCommand(Command):
# alias: Field
class GetItemFromFieldCommand(Command):
def __init__(self, token):
def __init__(self, game, token):
super().__init__()
self.game = game
self.token = token
self.item = None
def execute(self):
# TODO: get the item from the player's current position
pass
player = self.game.getPlayer(token = self.token)
if not player:
self.__error = True
else:
try:
self.item = player.takeItem(location = player.currentLocation)
# TODO: update the player's inventory in the db
except Exception, e:
self.__error = str(e)
def getStatus(self):
if not self.__error and self.result:
......@@ -277,29 +410,47 @@ class GetItemFromFieldCommand(Command):
class MakeItemOfferCommand(Command):
def __init__(self, token, offer_item, offer_itemCount, demand_item, demand_itemCount):
def __init__(self, game, token, offer_item, offer_itemCount, demand_item, demand_itemCount):
super().__init__()
self.token = token
self.game = game
self.token = token
self.offer_item = Item(id=offer_item, count=offer_itemCount)
self.demand_item = Item(id=demand_item, count=demand_itemCount)
def execute(self):
# TODO: make the offer
pass
try:
player = self.game.getPlayer(self.token)
if player:
player.makeOffer(self.offer_item, self.demand_item)
# TODO: add the offer to the global offer table, and update the player's offer table
else:
self.__error = True
except Exception, e:
self.__error = e
class TradeboxQueryCommand(Command):
def __init__(self, token):
def __init__(self, game, token):
super().__init__()
self.game = game
self.token = token
self.result = None
self.result = []
def execute(self):
# TODO: get the tradebox of the player
pass
try:
player = self.game.getPlayer(self.token)
if player:
for offer in enumerate(player.getTradebox()):
self.result.append(offer.asList())
else:
self.__error = True
except Exception, e:
self.__error = e
def getStatus(self):
if not self.__error and self.result:
......@@ -315,9 +466,10 @@ class TradeboxQueryCommand(Command):
class SendFindCommand(Command):
def __init__(self, token, itemId):
def __init__(self, game, token, itemId):
super().__init__()
self.game = game
self.token = token
self.item = itemId
......@@ -352,15 +504,30 @@ class FindOfferCommand(Command):
self.result = None
def execute(self):
# TODO: create a connection to such server, and send the query
pass
sock = socket.socket()
try:
sock.connect((self.ip, self.port))
sock.sendAll(json.dumps({
'method': Command.METHOD_FINDOFFER,
'item': self.item
}))
"""
This assumes that the server is going to send small-sized data.
Maybe in the future this needs to be revised, to handle arbitary-sized data.
"""
data = sock.recv(4096, 'utf-8')
self.result = json.loads(data)
except Exception, e:
self.__error = str(e)
finally:
sock.close()
def getStatus(self):
if not self.__error and self.result:
return {
'status': 'ok',
'offers': self.result
}
return self.result
else:
if not self.__error:
self.__error = True
......@@ -369,9 +536,10 @@ class FindOfferCommand(Command):
class SendItemAcceptOfferCommand(Command):
def __init__(self, token, offer_token):
def __init__(self, game, token, offer_token):
super().__init__()
self.game = game
self.token = token
self.offer_token = offer_token
......@@ -382,20 +550,26 @@ class SendItemAcceptOfferCommand(Command):
# NOTE: this is something that is sent by the server, not received by the server
class AcceptItemOfferCommand(Command):
def __init__(self, offer_token):
def __init__(self, offer_token, ip, port):
super().__init__()
self.token = token
self.offer_token = offer_token
self.ip = ip
self.port = port
self.result = None
def execute(self):
# TODO: accept the player's offer from other server
# Question: do we need to duplicate?
pass
class FetchOfferedItemCommand(Command):
def __init__(self, token, offer_token):
def __init__(self, game, token, offer_token):
super().__init__()
self.game = game
self.token = token
self.offer_token = offer_token
......@@ -404,9 +578,10 @@ class FetchOfferedItemCommand(Command):
pass
class CancelItemOfferCommand(Command):
def __init__(self, token, offer_token):
def __init__(self, game, token, offer_token):
super().__init__()
self.game = game
self.token = token
self.offer_token = offer_token
......
import pymongo
class Game(object):
DEFAULT_ID = 0
def __init__(self, id=Game.DEFAULT_ID):
super().__init__()
__loadGameData()
def __loadGameData(self):
pass
\ No newline at end of file
import pymongo
import json
import bcrypt
class Location(object):
def __init__(self, x, y):
super().__init__()
self.x = int(x)
self.y = int(y)
class GameMap(object):
def __init__(self, name, width, height, locations = None):
assert width > 0 and height > 0
super().__init__()
self.name = name
self.width = int(width)
self.height = int(height)
if not locations:
self.locations = [[None] * height] * width
else:
assert len(locations) == width and len(locations[0]) == height
self.locations = []
for elem in locations:
self.locations.append(elem)
class Game(object):
FILE_MAP = 'map.json'
DB_NAME = 'if3230-sister'
DB_COLLECTION_USERS = 'users'
__instance = None
def __init__(self, mapFile = FILE_MAP):
super().__init__()
# the attributes
self.players = []
self.map = None
with open(mapFile) as map_file:
self.__loadMap(json.load(mapFile))
self.__loadPlayers()
@classmethod
def getInstance(self):
if not Game.__instance:
Game.__instance = Game()
return Game.__instance
def __loadMap(self, json):
assert isinstance(json, dict)
self.