summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/conf.lua11
-rw-r--r--client/game.lua (renamed from client/main_1.lua)50
-rw-r--r--client/main.lua66
-rw-r--r--client/menu.lua106
-rw-r--r--server/server.lua40
5 files changed, 172 insertions, 101 deletions
diff --git a/client/conf.lua b/client/conf.lua
index dca36d1..1fea49a 100644
--- a/client/conf.lua
+++ b/client/conf.lua
@@ -1 +1,10 @@
-function love.conf(t) t.window.msaa=8 t.window.title='duet' end
+function love.conf(t)
+ t.window.msaa=8
+ t.window.title='duet'
+ t.identity='duet'
+
+ t.modules.physics = false
+ t.modules.joystick = false
+ t.modules.touch = false
+ t.modules.video = false
+end
diff --git a/client/main_1.lua b/client/game.lua
index f5ee5a9..59c5799 100644
--- a/client/main_1.lua
+++ b/client/game.lua
@@ -2,6 +2,7 @@ local G = love.graphics
local common = require 'common'
local Camera = require'r.camera'
local Pos = require'r.pos'
+local Rect = require'r.rect'
local class = require'r.class'
local enet = require'enet'
local pprint = require'pprint'
@@ -13,14 +14,16 @@ local M = {}
local SPEED = 8 -- tiles per second
local colors = {[true]={141/255,128/255,22/255}, [false]={71/255,50/255,122/255}}
-local host = enet.host_create()
-local conn = host:connect('localhost:19683')
local players = {}
local chunks = common.ChunkMap()
local lp = { pos=Pos(0,0), movetimer=0, dir=nil } -- local player
local cam = Camera(nil, 20)
+local host, conn
+function M.load(_host,_conn,j) host=_host conn=_conn
+ lp.pos=Pos(j.pos.x,j.pos.y) lp.name=j.name lp.color=j.color end
+
local directions = {w=Pos(0,-1),a=Pos(-1,0),s=Pos(0,1),d=Pos(1,0)}
function M.keypressed(k,s,r)
if directions[s] then
@@ -37,16 +40,23 @@ function lp.update(dt)
if chunks:tile(newpos) == false then
conn:send(json.encode{type='move',pos=newpos})
lp.pos = newpos lp.movetimer = 1 / SPEED end end end
-local function draw_player(p, c) G.setColor(c) G.circle('fill',p.x,p.y,0.3) end
-function lp.draw() draw_player(lp.pos, {0,1,0}) end
+local function draw_player(player,no_label)
+ G.setColor(player.color) G.circle('fill',player.pos.x,player.pos.y,0.3)
+ if not no_label then local f = G.getFont()
+ local txtw,h = f:getWidth(player.name), f:getHeight()
+ local centre = cam:world_to_screen(player.pos-Pos(0,.4))-Pos(0,h/2)
+ local bb = Rect:from_centre_dims(centre,txtw,h)
+ G.push() G.origin() G.setColor(0,0,0,0.8) bb:draw'fill'
+ G.setColor(1,1,1) G.print(player.name,bb.tl:vals()) G.pop() end end
+function lp.draw() draw_player(lp,true) end
function M.update(dt)
lp.update(dt)
- local ev = host:service() while ev do
+ local ev = host and host:service() while ev do
-- pprint(ev)
if ev.type == 'receive' then local j = json.decode(ev.data)
local pos if j.pos then pos = Pos(j.pos.x,j.pos.y) end
- if j.type == 'player' then players[j.name] = {name=j.name,pos=pos}
+ if j.type == 'player' then players[j.name] = {name=j.name,pos=pos,color=j.color}
elseif j.type == 'unplayer' then players[j.from] = nil
elseif j.type == 'move' then players[j.from].pos = pos
elseif j.type == 'chunk' then chunks:add(pos,{d=rle.decode(j.d)})
@@ -54,7 +64,7 @@ function M.update(dt)
elseif j.type == 'tile' then chunks:set_tile(pos,j.tile)
end
end
- ev = host:service()
+ ev = host and host:service()
end
end
function M.draw()
@@ -67,19 +77,19 @@ function M.draw()
local t = chunks:tile(Pos(x,y))
if t ~= nil then G.setColor(colors[t~=(x<0)]) G.rectangle('fill',x-0.5,y-0.5,1,1) end end end
lp.draw()
- for _,player in pairs(players) do draw_player(player.pos,{0,1,1}) end
- G.origin() G.setColor(1,0,0)
- G.print(tostring(lp.pos),100,100)
- G.setColor(0,0,0,0.8)
- G.rectangle('fill',0,0,100,100)
- G.setColor(1,1,1)
- for cx=-7,7 do for cy=-7,7 do local p=Pos(cx,cy) if chunks:get(p) then
- p = (p + Pos(7,7))*10
- G.setColor(1,1,1) G.rectangle('fill',p.x,p.y,10,10)
- G.setColor(0,0,1) G.rectangle('line',p.x,p.y,10,10)
- end end end
- local p = (lp.pos/common.SIZE+Pos(7,7))*10
- G.setColor(1,0,0) G.rectangle('fill',p.x-1,p.y-1,2,2)
+ for _,player in pairs(players) do draw_player(player) end
+ -- G.origin() G.setColor(1,0,0)
+ -- G.print(tostring(lp.pos),100,100)
+ -- G.setColor(0,0,0,0.8)
+ -- G.rectangle('fill',0,0,100,100)
+ -- G.setColor(1,1,1)
+ -- for cx=-7,7 do for cy=-7,7 do local p=Pos(cx,cy) if chunks:get(p) then
+ -- p = (p + Pos(7,7))*10
+ -- G.setColor(1,1,1) G.rectangle('fill',p.x,p.y,10,10)
+ -- G.setColor(0,0,1) G.rectangle('line',p.x,p.y,10,10)
+ -- end end end
+ -- local p = (lp.pos/common.SIZE+Pos(7,7))*10
+ -- G.setColor(1,0,0) G.rectangle('fill',p.x-1,p.y-1,2,2)
end
return M
diff --git a/client/main.lua b/client/main.lua
index 262d849..64358ab 100644
--- a/client/main.lua
+++ b/client/main.lua
@@ -1,65 +1 @@
-local Pos = require'r.pos'
-local Rect = require'r.rect'
-local class = require'r.class'
-local G = love.graphics
-local utf8 = require'utf8'
-
-local logo = G.newImage"logo.png" logo:setFilter'nearest'
-
-local function c(...) return {love.math.colorFromBytes(...)} end
--- taken from breadquest
-local colors = { c(255,64,64), c(255,128,0), c(192,192,64), c(0,192,0),
- c(0,192,192), c(64,64,255), c(192,0,192), c(128,128,128)}
-
-local state = {color=1,focused=nil,name='Susan'}
-
-local LogoImage = {}
-function LogoImage.draw() G.setColor(1,1,1) G.draw(logo, 120, 50, 0, 12) end
-
-local ColorButton = class()
-function ColorButton.make(cls, idx)
- local size, gap = 40, 10
- local tl = Pos(100,240) + (idx-1)*Pos(size+gap,0)
- local bb = Rect:from_pos(tl,tl+Pos(size,size))
- return setmetatable({bb=bb,idx=idx},cls) end
-function ColorButton.draw(self)
- G.setColor(colors[self.idx]) self.bb:draw'fill'
- if self.idx == state.color then G.setColor(0,0,0) local d=5
- G.line(self.bb.x0+d,self.bb.y0+d,self.bb.x1-d,self.bb.y1-d)
- G.line(self.bb.x0+d,self.bb.y1-d,self.bb.x1-d,self.bb.y0+d) end end
-function ColorButton.click(self) state.color = self.idx end
-
-local font = G.newFont(24)
-local NameField = class()
-function NameField.make(cls,org)
- local self = setmetatable({org=org},cls) self:setbb() return self end
-function NameField.setbb(self) local width = 12+math.max(200,font:getWidth(state.name))
- self.bb=Rect:from_xywh(self.org.x,self.org.y,width,font:getHeight()) end
-function NameField.draw(self) G.setColor(0,0,0) self.bb:draw'line' local d=3
- G.setFont(font) G.print(state.name,self.bb.x0+d,self.bb.y0)
- if self == state.focused then local w = 2*d+self.bb.x0+font:getWidth(state.name)
- G.line(w,self.bb.y0+d,w,self.bb.y1-d) end end
-function NameField.input(self,text) state.name = state.name .. text self:setbb() end
-function NameField.key(self,key) if key == 'backspace' and #state.name > 0 then
- state.name = state.name:sub(1,utf8.offset(state.name,-1)-1) self:setbb() end end
-
-local things = { NameField(Pos(100,400)), LogoImage }
-for i=1,#colors do table.insert(things, ColorButton(i)) end
-
-local function draw_ui() for _,thing in ipairs(things) do
- if thing.draw then thing:draw() end
- if thing.bb and thing.bb:has(Pos(love.mouse.getPosition())) then
- G.setColor(0,0,0) thing.bb:draw'line' end end end
-
-local function which(p) for _,thing in ipairs(things) do
- if thing.bb and thing.bb:has(p) then return thing end end end
-function love.draw() G.clear(1,1,1) draw_ui() end
-function love.mousepressed(x,y,button)
- local thing = which(Pos(x,y)) if thing then state.focused = thing
- if thing.click then thing:click() end end end
-love.keyboard.setKeyRepeat(true)
-function love.textinput(text) if state.focused and state.focused.input then
- state.focused:input(text) end end
-function love.keypressed(key) if state.focused and state.focused.key then
- state.focused:key(key) end end
-
+require'menu'
diff --git a/client/menu.lua b/client/menu.lua
new file mode 100644
index 0000000..a6eccfb
--- /dev/null
+++ b/client/menu.lua
@@ -0,0 +1,106 @@
+local Pos = require'r.pos'
+local Rect = require'r.rect'
+local class = require'r.class'
+local G = love.graphics
+local utf8 = require'utf8'
+local enet = require'enet'
+local json = require'dkjson'
+local pprint = require'pprint'
+local qw = require'r.qw'
+
+local logo = G.newImage"logo.png" logo:setFilter'nearest'
+
+local function c(...) return {love.math.colorFromBytes(...)} end
+-- taken from breadquest
+local colors = { c(255,64,64), c(255,128,0), c(192,192,64), c(0,192,0),
+ c(0,192,192), c(64,64,255), c(192,0,192), c(128,128,128)}
+
+local state = {color=1,focused=nil,name='Susan',errmsg=nil}
+local rstate = love.filesystem.read'menu.json'
+if rstate then for k,v in pairs(json.decode(rstate)) do state[k]=v end end
+
+local LogoImage = {}
+function LogoImage.draw() G.setColor(1,1,1) G.draw(logo, 120, 50, 0, 12) end
+
+local ColorButton = class()
+function ColorButton.make(cls, idx)
+ local size, gap = 40, 10
+ local tl = Pos(100,240) + (idx-1)*Pos(size+gap,0)
+ local bb = Rect:from_pos(tl,tl+Pos(size,size))
+ return setmetatable({bb=bb,idx=idx},cls) end
+function ColorButton.draw(self)
+ G.setColor(colors[self.idx]) self.bb:draw'fill'
+ if self.idx == state.color then G.setColor(0,0,0) local d=5
+ G.line(self.bb.x0+d,self.bb.y0+d,self.bb.x1-d,self.bb.y1-d)
+ G.line(self.bb.x0+d,self.bb.y1-d,self.bb.x1-d,self.bb.y0+d) end end
+function ColorButton.click(self) state.color = self.idx end
+
+local font = G.newFont(24)
+local bigfont = G.newFont(36)
+local NameField = class()
+function NameField.make(cls,org)
+ local self = setmetatable({org=org},cls) self:setbb() return self end
+function NameField.setbb(self) local width = 12+math.max(200,font:getWidth(state.name))
+ self.bb=Rect:from_xywh(self.org.x,self.org.y,width,font:getHeight()) end
+function NameField.draw(self) G.setColor(0,0,0) self.bb:draw'line' local d=3
+ G.setFont(font) G.print(state.name,self.bb.x0+d,self.bb.y0)
+ if self == state.focused then local w = 2*d+self.bb.x0+font:getWidth(state.name)
+ G.line(w,self.bb.y0+d,w,self.bb.y1-d) end end
+function NameField.input(self,text) state.name = state.name .. text self:setbb() end
+function NameField.key(self,key) if key == 'backspace' and #state.name > 0 then
+ state.name = state.name:sub(1,utf8.offset(state.name,-1)-1) self:setbb() end end
+
+local w,h = bigfont:getWidth"connecting...", bigfont:getHeight()
+local ConnectButton = { bb=Rect:from_xywh(100,400,w,h),c=false }
+function ConnectButton.draw(self) G.setColor(0,1,0.2) self.bb:draw'fill'
+ G.setColor(0,0,0) G.setFont(bigfont)
+ G.print(self.c and 'connecting...' or 'connect',self.bb.tl:vals()) end
+
+local ErrDisp = {draw=function() if state.errmsg then
+ G.setColor(1,0,0) G.setFont(font) G.print(state.errmsg,100,10) end end}
+
+local things = { NameField(Pos(100,300)), LogoImage, ConnectButton, ErrDisp }
+for i=1,#colors do table.insert(things, ColorButton(i)) end
+
+local function draw_ui() for _,thing in ipairs(things) do
+ if thing.draw then thing:draw() end
+ if thing.bb and thing.bb:has(Pos(love.mouse.getPosition())) then
+ G.setColor(0,0,0) thing.bb:draw'line' end end end
+
+local function which(p) for _,thing in ipairs(things) do
+ if thing.bb and thing.bb:has(p) then return thing end end end
+function love.draw() G.clear(1,1,1) draw_ui() end
+function love.mousepressed(x,y,button)
+ local thing = which(Pos(x,y)) if thing then state.focused = thing
+ if thing.click then thing:click() end end end
+love.keyboard.setKeyRepeat(true)
+function love.textinput(text) if state.focused and state.focused.input then
+ state.focused:input(text) end end
+function love.keypressed(key) if state.focused and state.focused.key then
+ state.focused:key(key) end end
+
+local host,conn
+function ConnectButton.click(self)
+ print(love.filesystem.write('menu.json',
+ json.encode{color=state.color,name=state.name}))
+ self.c = true host = enet.host_create() conn=host:connect"localhost:19683"end
+function ConnectButton.unclick(self)
+ self.c = false host=nil conn=nil end
+
+local function switch_scene(modname,...)
+ local mod = require(modname)
+ for k in qw.i"update keypressed textinput mousepressed draw" do
+ love[k] = nil end
+ for k,v in pairs(mod) do love[k] = v end
+ G.reset() if mod.load then mod.load(...) end
+end
+
+function love.update(dt)
+ local ev = host and host:service() while ev do
+ pprint(ev)
+ if ev.type == 'receive' then local j = json.decode(ev.data)
+ if j.type == 'you' then switch_scene('game',host,conn,j) return
+ elseif j.type == 'error' then print('hi') state.errmsg = j.msg conn:disconnect_later() ConnectButton:unclick()
+ end
+ elseif ev.type == 'connect' then conn:send(json.encode{type='hi',name=state.name,color=colors[state.color]}) end
+ ev = host and host:service() end end
diff --git a/server/server.lua b/server/server.lua
index a53d9a1..05549bd 100644
--- a/server/server.lua
+++ b/server/server.lua
@@ -20,9 +20,9 @@ local chunks = common.ChunkMap()
local Chunk = class()
function Chunk.make(cls, cp, d) local self = setmetatable({cp=cp,d=d},cls)
chunks:add(cp,self) return self end
-function Chunk.generate(cls,cp)
+function Chunk.generate(cls,cp) local offs=cp*SIZE
local d={} for x=0,SIZE-1 do for y=0,SIZE-1 do
- local nv = noise_gen:at(x,y) local fill = nv>0.06
+ local nv = noise_gen:at(offs.x+x,offs.y+y) local fill = nv>0.06
if math.random(3) == 2 then fill = not fill end
d[1+x*SIZE+y] = (cp.x<0) ~= fill end end
return cls(cp,d) end
@@ -41,9 +41,11 @@ function Chunk.obtain(cls,cp)
return cls:generate(cp) end
local Player = class()
-function Player.make(cls, obj) return setmetatable(obj,cls) end
+function Player.make(cls, peer, j)
+ return setmetatable({peer=peer, pos=Pos(0,0), name=j.name,
+ color=j.color, loaded={}}, cls) end
function Player.packet(self,packet_type)
- return json.encode { name=self.name, pos=self.pos, type=packet_type } end
+ return json.encode { name=self.name, pos=self.pos, color=self.color, type=packet_type } end
local players = {}
local function find_player(arg) local k,v = next(arg)
for pl in pairs(players) do if pl[k] == v then return pl end end end
@@ -52,8 +54,16 @@ local function send_others(player,data)
data.from = player.name local packet = json.encode(data)
for player2 in other_players(player) do player2.peer:send(packet) end end
+local function check(peer,j) -- new player
+ if not j.name or #j.name == 0 then return "please enter a name!" end
+ if #j.name >16 then return "name too long!" end
+ if find_player{name=j.name} then return "name already in use! pick a different one!" end
+end
+
local function greet(player)
print('greeting',player.name,player.peer)
+ players[player] = true
+ player.peer:send(player:packet'you')
for player2 in other_players(player) do
player.peer:send(player2:packet'player')
player2.peer:send(player:packet'player') end end
@@ -73,22 +83,22 @@ local function doctor_chunks()
for k,chunk in pairs(chunks.d) do local cp = Pos:unkey(k)
local used = false
for player in pairs(players) do if player.loaded[k] then used=true end end
- if not used then chunk:save() chunks:remove(cp) end end end
+ if not used then chunk:save() chunks:remove(cp) end end
+ if not next(chunks.d) then print'no chunks' end end
while true do
- local ev = host:service(100) if ev then
+ local ev = host:service(10000) if ev then
local peer = ev.peer local player = find_player{peer=peer}
- if ev.type=='connect' then
- print('connecting',peer)
- local player = Player{pos=Pos(0,0), peer=peer, name=next_name(), loaded={}}
- players[player] = true; greet(player)
- elseif ev.type=='disconnect' then
- print('disconnecting',peer)
- send_others(player, {type='unplayer'})
- players[player] = nil
+ if ev.type=='connect' then print('connecting',peer)
+ elseif ev.type=='disconnect' then print('disconnecting',peer)
+ if player then send_others(player, {type='unplayer'})
+ players[player] = nil end
elseif ev.type=='receive' then local j = json.decode(ev.data)
local pos if j.pos then pos = Pos(j.pos.x,j.pos.y) end
- if j.type == 'move' then player.pos=pos send_others(player, j)
+ if j.type == 'hi' and not player then local err = check(peer,j)
+ if err then peer:send(json.encode{type="error",msg=err}) peer:disconnect_later()
+ else greet(Player(peer,j)) end
+ elseif j.type == 'move' then player.pos=pos send_others(player, j)
elseif j.type == 'tile' then chunks:set_tile(pos,j.tile) send_others(player,j)
end
end