Finish multiplayer work
67
blocks.py
@ -4,7 +4,6 @@ import lib.constants as constants
|
||||
from lib.gameregistry import GameRegistry
|
||||
from lib.block import Block
|
||||
from lib.inventory import Inventory
|
||||
|
||||
dy_blocks={}
|
||||
|
||||
def make_block(klass_name,name,clear=False,drops=False):
|
||||
@ -35,7 +34,7 @@ make_block("BlockTree","tree",False,("wood",8))
|
||||
make_block("BlockGrass","grass",True)
|
||||
make_block("BlockWood","wood")
|
||||
make_block("BlockCoal","coal_ore")
|
||||
GameRegistry.registerFuel("coal",8)
|
||||
GameRegistry.registerFuel("coal_ore",8)
|
||||
make_block("BlockIron","iron_ore")
|
||||
make_block("ItemIronIngot","iron_ingot",False)
|
||||
#make_block("ItemCoal","coal",False)
|
||||
@ -63,6 +62,12 @@ class BlockDoor(Block):
|
||||
else:
|
||||
return False
|
||||
|
||||
def interactData(self):
|
||||
return {"clear":self.clear}
|
||||
|
||||
def loadData(self,data):
|
||||
self.clear=data["clear"]
|
||||
|
||||
class BlockWorkbench(Block):
|
||||
unlocalisedName="workbench"
|
||||
|
||||
@ -92,6 +97,12 @@ class BlockWorkbench(Block):
|
||||
inv.addTile(out,1)
|
||||
self.inv.clear()
|
||||
|
||||
def interactData(self):
|
||||
return {"inv":self.inv}
|
||||
|
||||
def loadData(self,data):
|
||||
self.inv=data["inv"]
|
||||
|
||||
class BlockFurnace(Block):
|
||||
unlocalisedName="furnace"
|
||||
frames=[]
|
||||
@ -120,6 +131,8 @@ class BlockFurnace(Block):
|
||||
self.fuel=""
|
||||
self.fuel_amount=0
|
||||
self.fuel_num=0
|
||||
self.originator=True
|
||||
|
||||
def interact(self,inv):
|
||||
sel=inv.selected
|
||||
if sel!="":
|
||||
@ -149,11 +162,11 @@ class BlockFurnace(Block):
|
||||
inv.addTile(self.outp,self.outp_amount)
|
||||
self.outp=""
|
||||
self.outp_amount=0
|
||||
self.originator=True
|
||||
|
||||
def getTexture(self):
|
||||
if self.burn:
|
||||
self.count+=1
|
||||
print(self.count)
|
||||
if self.count==10:
|
||||
self.update()
|
||||
self.count=0
|
||||
@ -171,14 +184,15 @@ class BlockFurnace(Block):
|
||||
return img
|
||||
else:
|
||||
return False
|
||||
self.mp_upd=True
|
||||
|
||||
def update(self):
|
||||
self.fuel_num-=1
|
||||
if self.fuel_num==0:
|
||||
if self.inp=="":
|
||||
self.burn=False
|
||||
return
|
||||
if self.fuel_amount==0:
|
||||
if self.inp=="":
|
||||
self.burn=False
|
||||
return
|
||||
if self.fuel_num<=0:
|
||||
if self.fuel_amount<=0:
|
||||
self.burn=False
|
||||
self.fuel=""
|
||||
return
|
||||
@ -186,12 +200,41 @@ class BlockFurnace(Block):
|
||||
self.fuel_amount-=1
|
||||
self.fuel_num=GameRegistry.fuels[self.fuel]
|
||||
if self.inp!="":
|
||||
print("CRAFT {}".format(self.inp))
|
||||
if self.inp in GameRegistry.smelting:
|
||||
print("GA")
|
||||
self.inp_amount-=1
|
||||
self.outp=GameRegistry.smelting[self.inp]
|
||||
self.outp_amount+=1
|
||||
if self.inp_amount==0:
|
||||
if self.inp_amount<=0:
|
||||
self.inp=""
|
||||
print("{} {} in output".format(self.outp_amount,self.outp))
|
||||
if self.originator:
|
||||
self.mp_upd=True
|
||||
|
||||
def loadData(self,data):
|
||||
self.frameno=data["frameno"]
|
||||
self.forward=data["forward"]
|
||||
self.burn=data["burn"]
|
||||
self.count=data["count"]
|
||||
self.inp=data["inp"]
|
||||
self.inp_amount=data["inp_amount"]
|
||||
self.outp=data["outp"]
|
||||
self.outp_amount=data["outp_amount"]
|
||||
self.fuel=data["fuel"]
|
||||
self.fuel_amount=data["fuel_amount"]
|
||||
self.fuel_num=data["fuel_num"]
|
||||
self.originator=False
|
||||
|
||||
def interactData(self):
|
||||
self.mp_upd=False
|
||||
return {
|
||||
"frameno":self.frameno,
|
||||
"forward":self.forward,
|
||||
"burn":self.burn,
|
||||
"count":self.count,
|
||||
"inp":self.inp,
|
||||
"inp_amount":self.inp_amount,
|
||||
"outp":self.outp,
|
||||
"outp_amount":self.outp_amount,
|
||||
"fuel":self.fuel,
|
||||
"fuel_amount":self.fuel_amount,
|
||||
"fuel_num":self.fuel_num
|
||||
}
|
||||
|
133
client.py
@ -7,12 +7,14 @@ import select
|
||||
import blocks
|
||||
import socket
|
||||
import pickle
|
||||
import math
|
||||
import lib.constants as constants
|
||||
from lib.gameregistry import GameRegistry
|
||||
from lib.map import Map
|
||||
from lib.character import Character
|
||||
from lib.block import Block
|
||||
from player import *
|
||||
from player_img import *
|
||||
from time import sleep
|
||||
|
||||
def recv_str(sock,print_str=True):
|
||||
@ -23,12 +25,12 @@ def recv_str(sock,print_str=True):
|
||||
if ch=="\n":
|
||||
break
|
||||
str+=ch
|
||||
if print_str:
|
||||
print(str)
|
||||
# if print_str:
|
||||
# print(str)
|
||||
return str
|
||||
|
||||
def send_str(sock,str):
|
||||
print(str)
|
||||
# print(str)
|
||||
sock.send((str+"\n").encode("utf-8"))
|
||||
|
||||
def recv_hash(sock):
|
||||
@ -38,7 +40,7 @@ def recv_hash(sock):
|
||||
key=recv_str(sock,False)
|
||||
val=recv_str(sock,False)
|
||||
hash[key]=val
|
||||
print(hash)
|
||||
# print(hash)
|
||||
return hash
|
||||
|
||||
def recvall(sock):
|
||||
@ -66,7 +68,6 @@ uid_map={}
|
||||
send_str(sock,"GET_MAP")
|
||||
data=recvall(sock)
|
||||
map=pickle.loads(data)
|
||||
sleep(0.5)
|
||||
# The server's generated map does not have a screen. We fix that here.
|
||||
map.screen=screen
|
||||
for s in map.sprites():
|
||||
@ -75,7 +76,10 @@ send_str(sock,"GET_POS_FOR_UID")
|
||||
send_str(sock,str(my_uid))
|
||||
x=int(recv_str(sock))*constants.TILESIZE
|
||||
y=int(recv_str(sock))*constants.TILESIZE
|
||||
player=Player(x,y,map,screen,UNAME,"player")
|
||||
fac=recv_str(sock)
|
||||
player=Player(x,y,map,screen,UNAME,"player_local")
|
||||
player.inv.addTile("workbench",1)
|
||||
player.dir=fac
|
||||
others={}
|
||||
running=True
|
||||
move=False
|
||||
@ -94,27 +98,138 @@ while running:
|
||||
connected=[]
|
||||
for uname,uid in uid_map.items():
|
||||
if uname!=UNAME:
|
||||
print("Getting {}'s position".format(uname))
|
||||
send_str(sock,"GET_POS_FOR_UID")
|
||||
send_str(sock,uid)
|
||||
x=int(recv_str(sock))*constants.TILESIZE
|
||||
y=int(recv_str(sock))*constants.TILESIZE
|
||||
fac=recv_str(sock)
|
||||
if uname in others:
|
||||
others[uname].x=x
|
||||
others[uname].y=y
|
||||
else:
|
||||
others[uname]=Player(x,y,map,screen,uname,"slime")
|
||||
others[uname]=PlayerImg(x,y,screen,"player")
|
||||
others[uname].dir=fac
|
||||
connected.append(uname)
|
||||
# Remove all disconnected players
|
||||
others_copy=others.copy()
|
||||
for uname,uid in others_copy.items():
|
||||
if not uname in connected:
|
||||
del others[uname]
|
||||
send_str(sock,"GET_CHANGES_FOR")
|
||||
send_str(sock,str(my_uid))
|
||||
data=recvall(sock)
|
||||
changes=pickle.loads(data)
|
||||
for change in changes:
|
||||
if change["type"]=="break":
|
||||
x=change["x"]
|
||||
y=change["y"]
|
||||
tile=map.tileAt(x,y)
|
||||
name=tile.unlocalisedName
|
||||
if name=="grass":
|
||||
continue
|
||||
map.remove(tile)
|
||||
map.addTile("grass",x,y)
|
||||
if change["type"]=="place":
|
||||
x=change["x"]
|
||||
y=change["y"]
|
||||
block=change["block"]
|
||||
tile=map.tileAt(x,y)
|
||||
map.remove(tile)
|
||||
map.addTile(block,x,y)
|
||||
if change["type"]=="interact":
|
||||
x=change["x"]
|
||||
y=change["y"]
|
||||
block_data=change["block_data"]
|
||||
tile=map.tileAt(x,y)
|
||||
tile.loadData(block_data)
|
||||
for s in map.sprites():
|
||||
if s.mp_upd:
|
||||
data=s.interactData()
|
||||
send_str(sock,"INTERACT_BLOCK_AT")
|
||||
send_str(sock,str(my_uid))
|
||||
send_str(sock,str(math.floor(s.x)))
|
||||
send_str(sock,str(math.floor(s.y)))
|
||||
data_string=pickle.dumps(data)
|
||||
sock.send(data_string)
|
||||
if select.select([sys.stdin],[],[],0.0)[0]:
|
||||
cmd=input()
|
||||
cmd=cmd.split()
|
||||
if cmd[0]=="give":
|
||||
if len(cmd)==2:
|
||||
item=cmd[1]
|
||||
player.inv.addTile(item,1)
|
||||
elif len(cmd)==3:
|
||||
item=cmd[1]
|
||||
count=int(cmd[2])
|
||||
player.inv.addTile(item,count)
|
||||
else:
|
||||
print("give <item> [count]")
|
||||
for event in pygame.event.get():
|
||||
if event.type==pygame.QUIT:
|
||||
running=False
|
||||
elif event.type==pygame.KEYDOWN:
|
||||
if event.key==pygame.K_PERIOD:
|
||||
coords=player.facingTile()
|
||||
if coords!=False:
|
||||
tile=map.tileAt(coords[0],coords[1])
|
||||
name=tile.unlocalisedName
|
||||
if name=="grass":
|
||||
to_place=player.inv.selected
|
||||
if to_place!="":
|
||||
send_str(sock,"PLACE_BLOCK_AT")
|
||||
send_str(sock,str(my_uid))
|
||||
send_str(sock,str(math.floor(coords[0])))
|
||||
send_str(sock,str(math.floor(coords[1])))
|
||||
send_str(sock,str(to_place))
|
||||
player.interact()
|
||||
else:
|
||||
player.interact()
|
||||
tile=map.tileAt(coords[0],coords[1])
|
||||
data=tile.interactData()
|
||||
if data!=None:
|
||||
send_str(sock,"INTERACT_BLOCK_AT")
|
||||
send_str(sock,str(my_uid))
|
||||
send_str(sock,str(math.floor(coords[0])))
|
||||
send_str(sock,str(math.floor(coords[1])))
|
||||
data_string=pickle.dumps(data)
|
||||
sock.send(data_string)
|
||||
if event.key==pygame.K_SLASH:
|
||||
player.attack()
|
||||
facing=player.facingTile()
|
||||
if facing!=False:
|
||||
x=facing[0]
|
||||
y=facing[1]
|
||||
send_str(sock,"BREAK_BLOCK_AT")
|
||||
send_str(sock,str(my_uid))
|
||||
send_str(sock,str(math.floor(x)))
|
||||
send_str(sock,str(math.floor(y)))
|
||||
if event.key==pygame.K_j:
|
||||
player.inv.selPrev()
|
||||
if event.key==pygame.K_k:
|
||||
player.inv.clearSel()
|
||||
if event.key==pygame.K_l:
|
||||
player.inv.selNext()
|
||||
if event.key==pygame.K_e:
|
||||
inv=not inv
|
||||
if event.key==pygame.K_i:
|
||||
dy_blocks=blocks.dy_blocks
|
||||
Block.textures={}
|
||||
Block.init()
|
||||
for klass,unName in dy_blocks.items():
|
||||
Block.registerTexture(unName)
|
||||
elif event.key in key_to_dir.keys():
|
||||
move=True
|
||||
dir=key_to_dir[event.key]
|
||||
elif event.type==pygame.KEYUP:
|
||||
move=False
|
||||
player.frame=1
|
||||
if move:
|
||||
player.move(dir)
|
||||
send_str(sock,"SET_POS_FOR_UID")
|
||||
send_str(sock,str(my_uid))
|
||||
send_str(sock,str(math.floor(player.x/constants.TILESIZE)))
|
||||
send_str(sock,str(math.floor(player.y/constants.TILESIZE)))
|
||||
send_str(sock,player.dir)
|
||||
if inv:
|
||||
screen.fill([255,255,255])
|
||||
text=[]
|
||||
@ -137,7 +252,7 @@ while running:
|
||||
for uname,other in others.items():
|
||||
other.draw()
|
||||
pygame.display.flip()
|
||||
sleep(0.5)
|
||||
sleep(0.1)
|
||||
send_str(sock,"CLOSE")
|
||||
send_str(sock,UNAME)
|
||||
sock.close()
|
||||
|
12
lib/block.py
@ -20,10 +20,10 @@ class Block(Sprite):
|
||||
self.clear=False
|
||||
self.unlocalisedName=""
|
||||
self.drops=False
|
||||
|
||||
self.mp_upd=False
|
||||
def draw(self):
|
||||
if self.tname==None:
|
||||
raise Exception("No texture name for block. Did you forget to call setTextureName({})?".format(name))
|
||||
raise Exception("No texture name for block. Did you forget to call setTextureName()?".format())
|
||||
self.screen.blit(Block.background,(self.x*constants.TILESIZE,self.y*constants.TILESIZE))
|
||||
texture=self.getTexture()
|
||||
if texture==False:
|
||||
@ -32,7 +32,7 @@ class Block(Sprite):
|
||||
|
||||
def setTextureName(self,name):
|
||||
if not name in Block.textures.keys():
|
||||
raise Exception("{} is not a valid texture. Did you forget to call registerTexture({})?".format(name,name))
|
||||
raise Exception("{} is not a valid texture. Did you forget to call registerTexture(\"{}\")?".format(name,name))
|
||||
self.tname=name
|
||||
|
||||
@classmethod
|
||||
@ -44,3 +44,9 @@ class Block(Sprite):
|
||||
|
||||
def getTexture(self):
|
||||
return False
|
||||
|
||||
def interactData(self):
|
||||
return None
|
||||
|
||||
def loadData(self,data):
|
||||
pass
|
||||
|
@ -27,6 +27,7 @@ class Player(Character):
|
||||
if y<0:
|
||||
return False
|
||||
return (x,y)
|
||||
|
||||
def interact(self):
|
||||
coords=self.facingTile()
|
||||
if coords==False:
|
||||
|
34
player_img.py
Normal file
@ -0,0 +1,34 @@
|
||||
from pygame.sprite import Sprite
|
||||
import pygame.image
|
||||
import os
|
||||
import lib.constants as constants
|
||||
class PlayerImg(Sprite):
|
||||
@staticmethod
|
||||
def loadFrames(type):
|
||||
frames={}
|
||||
dirs=["up","down","left","right"]
|
||||
num_frames=3
|
||||
for dir in dirs:
|
||||
frame_array=[0,0,0]
|
||||
i=0
|
||||
while i<num_frames:
|
||||
img_name="{}_{}.png".format(dir,i)
|
||||
frame_array[i]=pygame.image.load(os.path.join("sprites",type,img_name))
|
||||
i+=1
|
||||
frames[dir]=frame_array
|
||||
return frames
|
||||
|
||||
def __init__(self,x,y,screen,type,*groups):
|
||||
super().__init__(groups)
|
||||
self.x=x
|
||||
self.y=y
|
||||
self.screen=screen
|
||||
self.frames=self.loadFrames(type)
|
||||
self.frame=1
|
||||
self.dir="right"
|
||||
self.map=map
|
||||
|
||||
def draw(self):
|
||||
img=self.frames[self.dir][self.frame]
|
||||
self.screen.blit(img,(self.x,self.y))
|
||||
pygame.display.flip()
|
@ -4,4 +4,4 @@ def init():
|
||||
GameRegistry.registerCrafting({"wood":6},"door")
|
||||
GameRegistry.registerCrafting({"wood":4},"workbench")
|
||||
GameRegistry.registerCrafting({"stone":8},"furnace")
|
||||
GameRegistry.registerSmelting("iron","wood")
|
||||
GameRegistry.registerSmelting("iron_ore","wood")
|
||||
|
97
serv.py
@ -16,7 +16,10 @@ from lib.block import Block
|
||||
from player import *
|
||||
from time import sleep
|
||||
uid_map={}
|
||||
pos_map={}
|
||||
map_changes={}
|
||||
next_uid=0
|
||||
|
||||
def recv_str(sock):
|
||||
str=""
|
||||
ch=""
|
||||
@ -36,19 +39,36 @@ def send_hash(sock,hash):
|
||||
send_str(sock,str(key))
|
||||
send_str(sock,str(val))
|
||||
|
||||
def recvall(sock):
|
||||
BUFF_SIZE=4096
|
||||
data=b''
|
||||
while True:
|
||||
part=sock.recv(BUFF_SIZE)
|
||||
data+=part
|
||||
if len(part)<BUFF_SIZE:
|
||||
break
|
||||
return data
|
||||
|
||||
def on_new_client(sock):
|
||||
global uid_map
|
||||
global next_uid
|
||||
global pos_map
|
||||
global map
|
||||
while True:
|
||||
msg=recv_str(sock)
|
||||
if msg=="CLOSE":
|
||||
uname=recv_str(sock)
|
||||
uid=uid_map[uname]
|
||||
del uid_map[uname]
|
||||
del pos_map[uid]
|
||||
del map_changes[uid]
|
||||
elif msg=="ADD_USR":
|
||||
uname=recv_str(sock)
|
||||
uid_map[uname]=next_uid
|
||||
resp=str(next_uid)
|
||||
send_str(sock,resp)
|
||||
pos_map[next_uid]=(next_uid,0,"down")
|
||||
map_changes[next_uid]=[]
|
||||
next_uid+=1
|
||||
elif msg=="GET_UID_MAP":
|
||||
send_hash(sock,uid_map)
|
||||
@ -57,12 +77,83 @@ def on_new_client(sock):
|
||||
sock.send(data_string)
|
||||
elif msg=="GET_POS_FOR_UID":
|
||||
uid=recv_str(sock)
|
||||
send_str(sock,uid)
|
||||
send_str(sock,"0")
|
||||
if not int(uid) in uid_map.values():
|
||||
print("Invalid UID {}".format(uid))
|
||||
sock.close()
|
||||
return
|
||||
pos=pos_map[int(uid)]
|
||||
send_str(sock,str(pos[0]))
|
||||
send_str(sock,str(pos[1]))
|
||||
send_str(sock,pos[2])
|
||||
elif msg=="SET_POS_FOR_UID":
|
||||
uid=int(recv_str(sock))
|
||||
if not int(uid) in uid_map.values():
|
||||
print("Invalid UID {}".format(uid))
|
||||
sock.close()
|
||||
return
|
||||
x=int(recv_str(sock))
|
||||
y=int(recv_str(sock))
|
||||
fac=recv_str(sock)
|
||||
pos_map[uid]=(x,y,fac)
|
||||
elif msg=="BREAK_BLOCK_AT":
|
||||
ch_uid=int(recv_str(sock))
|
||||
if not int(ch_uid) in uid_map.values():
|
||||
print("Invalid UID {}".format(uid))
|
||||
sock.close()
|
||||
return
|
||||
x=int(recv_str(sock))
|
||||
y=int(recv_str(sock))
|
||||
for uid,changes in map_changes.copy().items():
|
||||
if ch_uid!=uid:
|
||||
map_changes[uid].append({"type":"break","x":x,"y":y})
|
||||
tile=map.tileAt(x,y)
|
||||
name=tile.unlocalisedName
|
||||
if name=="grass":
|
||||
continue
|
||||
map.remove(tile)
|
||||
map.addTile("grass",x,y)
|
||||
elif msg=="PLACE_BLOCK_AT":
|
||||
ch_uid=int(recv_str(sock))
|
||||
if not int(ch_uid) in uid_map.values():
|
||||
print("Invalid UID {}".format(uid))
|
||||
sock.close()
|
||||
return
|
||||
x=int(recv_str(sock))
|
||||
y=int(recv_str(sock))
|
||||
block=recv_str(sock)
|
||||
for uid,changes in map_changes.copy().items():
|
||||
if ch_uid!=uid:
|
||||
map_changes[uid].append({"type":"place","x":x,"y":y,"block":block})
|
||||
tile=map.tileAt(x,y)
|
||||
map.remove(tile)
|
||||
map.addTile(block,x,y)
|
||||
elif msg=="INTERACT_BLOCK_AT":
|
||||
ch_uid=int(recv_str(sock))
|
||||
if not int(ch_uid) in uid_map.values():
|
||||
print("Invalid UID {}".format(uid))
|
||||
sock.close()
|
||||
return
|
||||
x=int(recv_str(sock))
|
||||
y=int(recv_str(sock))
|
||||
data=recvall(sock)
|
||||
block_data=pickle.loads(data)
|
||||
for uid,changes in map_changes.copy().items():
|
||||
if ch_uid!=uid:
|
||||
map_changes[uid].append({"type":"interact","x":x,"y":y,"block_data":block_data})
|
||||
elif msg=="GET_CHANGES_FOR":
|
||||
uid=int(recv_str(sock))
|
||||
if not int(uid) in uid_map.values():
|
||||
print("Invalid UID {}".format(uid))
|
||||
sock.close()
|
||||
return
|
||||
changes=map_changes[uid]
|
||||
data_string=pickle.dumps(changes)
|
||||
sock.send(data_string)
|
||||
map_changes[uid]=[]
|
||||
clientsocket.close()
|
||||
|
||||
Block.init()
|
||||
map=Map(None)
|
||||
global s
|
||||
s=socket.socket()
|
||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
host="localhost"
|
||||
|
BIN
sprites/player_local/down_0.png
Normal file
After Width: | Height: | Size: 299 B |
BIN
sprites/player_local/down_1.png
Normal file
After Width: | Height: | Size: 292 B |
BIN
sprites/player_local/down_2.png
Normal file
After Width: | Height: | Size: 299 B |
BIN
sprites/player_local/left_0.png
Normal file
After Width: | Height: | Size: 296 B |
BIN
sprites/player_local/left_1.png
Normal file
After Width: | Height: | Size: 280 B |
BIN
sprites/player_local/left_2.png
Normal file
After Width: | Height: | Size: 306 B |
BIN
sprites/player_local/right_0.png
Normal file
After Width: | Height: | Size: 305 B |
BIN
sprites/player_local/right_1.png
Normal file
After Width: | Height: | Size: 279 B |
BIN
sprites/player_local/right_2.png
Normal file
After Width: | Height: | Size: 299 B |
BIN
sprites/player_local/up_0.png
Normal file
After Width: | Height: | Size: 286 B |
BIN
sprites/player_local/up_1.png
Normal file
After Width: | Height: | Size: 281 B |
BIN
sprites/player_local/up_2.png
Normal file
After Width: | Height: | Size: 289 B |