Finish multiplayer work

This commit is contained in:
pjht 2018-08-27 18:49:31 -05:00
parent df0c880c01
commit b4fec029e7
19 changed files with 318 additions and 28 deletions

View File

@ -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
View File

@ -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()

View File

@ -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

View File

@ -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
View 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()

View File

@ -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
View File

@ -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"

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 296 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 305 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 B