Posted 06 April 2015 - 04:31 PM
This will be a game where you can build stuff and allows you to play with other people. I currently have a few blocks in the script and will add more features.
The problem I need to fix is a bug that results in block updates not updating the terrain in the game, client or server side. Clicking on the screen is supposed to cause the block you clicked to turn into dirt or grass, however it is not updating my world at all. It sends chunk information just fine, so why can't it update a single block??
Here is the script source.
The problem I need to fix is a bug that results in block updates not updating the terrain in the game, client or server side. Clicking on the screen is supposed to cause the block you clicked to turn into dirt or grass, however it is not updating my world at all. It sends chunk information just fine, so why can't it update a single block??
Here is the script source.
local tArgs = {...}
term.redirect(term.native())
print("Please Wait...")
local sides = {"left", "right", "front", "back", "top", "bottom"}
local serialize, unserialize = textutils.serialize, textutils.unserialize
local scrwidth, scrheight = term.getSize()
local scrcenx, scrceny = math.floor(scrwidth*.5), math.ceil(scrheight*.5)
--term.setBackgroundColor(colors.blue)
local function yield()
os.queueEvent( "sleep" )
coroutine.yield( "sleep" )
end
-- Find a modem
function getModem()
while true do
for k, v in ipairs(sides) do
if peripheral.getType(v) == "modem" then
selectedside = v
return v
end
end
sleep()
end
end
getModem()
rednet.open(selectedside)
local draw = {}
local world = {}
local save = {}
local server = {}
local client = {}
local colorTab = {["0"] = 1, ["1"] = 2, ["2"] = 2^2, ["3"] = 2^3, ["4"] = 2^4, ["5"] = 2^5, ["6"] = 2^6, ["7"] = 2^7, ["8"] = 2^8, ["9"] = 2^9, ["A"] = 2^10, ["B"] = 2^11, ["C"] = 2^12, ["D"] = 2^13, ["E"] = 2^14, ["F"] = 2^15}
local blocks = {
{"3", "3", " "}, {"7", "8", "-"}, {"7", "8", "0"}, {"5", "C", "~"}, {"C", "C", " "}, {"9", "8", "8"}, {"C", "8", "8"}
}
local servertimer = os.startTimer(.25)
local myCom = os.getComputerID()
local localposx, localposy = 0, 0
-- set table variables
world.currentWorld = "NewWorld"
world.terrain = {}
world.renderDistance = 4
world.seed = 1
save.savedFilesDirectory = "CrBu/"
server.connected = {}
server.coTab = {}
client.connectedTo = -1
-- Draw API --
function draw.clear()
term.setCursorPos(1, 1)
term.clear()
end
function draw.setColorsToBlock(blockID)
term.setTextColor(colorTab[blocks[blockID][1]])
term.setBackgroundColor(colorTab[blocks[blockID][2]])
end
function draw.terrainChunk(x, y)
local localposx, localposy = localposx - scrcenx, localposy - scrceny
local setColorsToBlock = draw.setColorsToBlock
--term.clear()
if not world.terrain[x] then return end
if not world.terrain[x][y] then return end
local chunk = world.terrain[x][y]
local x, y = x*16, y*16
for x2=1, 16 do
for y2=1, 16 do
if y2 + y - localposy > 0 and y2 + y - localposy <= scrheight and x2 + x - localposx > 0 and x2 + x - localposx <= scrwidth then
if chunk[x2][y2][1] > 1 then
setColorsToBlock(chunk[x2][y2][1])
term.setCursorPos((x2 + x) - localposx, (y2 + y) - localposy)
term.write(blocks[chunk[x2][y2][1]][3])
end
end
end
end
end
-- Draws the terrain.
function draw.terrain()
local localposx, localposy = localposx - scrcenx, localposy - scrceny
local size = world.renderDistance
for x=-size + math.floor(localposx/16), size + math.floor(localposx/16) do
for y=-size + math.floor(localposy/16), size + math.floor(localposy/16) do
draw.terrainChunk(x, y)
end
end
end
-- Draws the heads up display.
function draw.hud()
term.setTextColor(colors.white)
term.setBackgroundColor(colors.black)
term.setCursorPos(1, 1)
term.write("Position: "..localposx..", "..localposy)
end
-- Draws the player list.
function draw.playerList()
end
-- Use this to draw a game frame.
function draw.game()
term.setBackgroundColor(colors.blue)
term.clear()
draw.terrain()
draw.hud()
term.setCursorPos(scrcenx, scrceny)
term.write("A")
end
-- World API --
function world.generateChunk(x, y)
--print("Generating chunk "..x, y)
if not world.terrain[x] then
world.terrain[x] = {}
end
if not world.terrain[x][y] then
world.terrain[x][y] = {}
end
local chunk = world.terrain[x][y]
for x2=1, 16 do
chunk[x2] = {}
for y2=1, 16 do
if y2 + y*16 < -127 then -- Generate Air
chunk[x2][y2] = {1}
elseif y2 + y*16 < -126 then -- Generate Grass
chunk[x2][y2] = {4}
elseif y2 + y*16 < -123 then -- Generate Dirt
chunk[x2][y2] = {5}
else
if math.random() > .98 then
chunk[x2][y2] = {6}
elseif math.random() > .88 then
chunk[x2][y2] = {7}
else
chunk[x2][y2] = {2}
end
end
end
end
end
function world.unloadChunk(x, y)
save.saveChunk(x, y)
world.terrain[x][y] = nil
end
-- Save API --
function save.saveChunk(x, y)
local chunk = world.terrain[x][y]
end
-- Saves the world.
function save.saveWorld()
end
function save.loadChunk(x, y)
world.generateChunk(x, y)
end
function save.loadWorld()
end
-- Server API --
-- Run when a new player has connected for the first time
function server.newPlayer(player)
server.connected[player] = {0, 0}
end
function server.loadPlayer(player)
server.connected[player] = {0, 0}
--local file =
end
-- Used to set up a player for gameplay
function server.initalizePlayer(player)
if fs.exists(save.savedFilesDirectory..world.currentWorld.."/"..player) then
server.newPlayer(player)
else
server.loadPlayer(player)
end
end
-- Used to safely unload the player's inventory
function server.savePlayer(player)
end
-- Coroutine that sends a chunk to a player.
function server.sendChunk(player, x, y)
if world.terrain[x] then
if not world.terrain[x][y] then
save.loadChunk(x, y)
end
else
save.loadChunk(x, y)
end
local message = serialize({"Requested Chunk", x, y, world.terrain[x][y]})
for k=1, 4 do
rednet.send(player, message)
sleep()
end
end
-- Coroutine that handles a server.
function server.handleServer()
end
function server.shutDownServer()
end
-- Run when the timer runs out so we send an update to the computers
function server.sendUpdate()
--servertimer = os.startTimer(.25)
end
function server.isPlayerConnected()
return true
end
function server.updateBlock(chunkX, chunkY, x, y, value)
print("Received Block Update.")
world.terrain[chunkX][chunkY][x][y] = value
local string = serialize({"Block Updated", chunkX, chunkY, x, y, value})
for k=1, 2 do
sleep()
rednet.broadcast(string)
end
end
function server.hearEvents()
while true do
--yield()
for k, v in pairs(server.coTab) do
if coroutine.status(v) ~= "dead" then
coroutine.resume(v)
end
end
local event, p1, p2, p3, p4, p5 = os.pullEvent()
if event == "timer" then
server.sendUpdate()
elseif event == "rednet_message" then
if p2 == "Connect" then
server.initalizePlayer(p1)
elseif server.isPlayerConnected(p1) then
local values = unserialize(p2)
if values[1] == "Chat" then
--rednet.broadcast()
elseif values[1] == "Update Block" then
local v = values
rednet.broadcast(serialize({"Block Updated", v[2], v[3], v[4], v[5], v[6]}))
--local co, err = coroutine.create(server.updateBlock, tonumber(v[2]), tonumber(v[3]), tonumber(v[4]), tonumber(v[5]), tonumber(v[6]))
--print(coroutine.resume(co, v[2], v[3], v[4], v[5], v[6]))
--server.coTab[#server.coTab + 1] = co
elseif values[1] == "NeedsNewChunk" then
local co, err = coroutine.create(server.sendChunk, p1, tonumber(values[2]), tonumber(values[3]))
coroutine.resume(co, p1, values[2], values[3])
server.coTab[#server.coTab + 1] = co
elseif values[1] == "Move Left" then
server.connected[p1][1] = server.connected[p1][1] - 1
rednet.send(p1, serialize({"Position Update", server.connected[p1][1], server.connected[p1][2]}))
elseif values[1] == "Move Right" then
server.connected[p1][1] = server.connected[p1][1] + 1
rednet.send(p1, serialize({"Position Update", server.connected[p1][1], server.connected[p1][2]}))
elseif values[1] == "Move Up" then
server.connected[p1][2] = server.connected[p1][2] - 1
rednet.send(p1, serialize({"Position Update", server.connected[p1][1], server.connected[p1][2]}))
elseif values[1] == "Move Down" then
server.connected[p1][2] = server.connected[p1][2] + 1
rednet.send(p1, serialize({"Position Update", server.connected[p1][1], server.connected[p1][2]}))
elseif values[1] == "Disconnect" then
server.coTab[#server.coTab + 1] = coroutine.create(server.savePlayer, p1)
end
end
end
end
end
function server.initalizeServer()
server.isServer = true
-- Now that server has started connect to the internal server.
while true do
parallel.waitForAny(server.hearEvents, client.handleClient)
--sleep()
end
end
-- Client API --
-- Sends an update to the server.
function client.sendUpdate(values)
for i=1, 1 do
sleep()
rednet.send(client.connectedTo, serialize(values))
end
end
function client.loadChunksInitial(sz)
for x=math.floor(localposx/16) - sz, math.floor(localposx/16) + sz do
if not world.terrain[x] then world.terrain[x] = {} end
for y=math.floor(localposy/16) - sz, math.floor(localposy/16) + sz do
client.sendUpdate({"NeedsNewChunk", x, y})
--sleep()
end
end
end
function client.loadChunksCoroutine(sz)
while true do
for x=math.floor(localposx/16) - sz, math.floor(localposx/16) + sz do
if not world.terrain[x] then world.terrain[x] = {} end
for y=math.floor(localposy/16) - sz, math.floor(localposy/16) + sz do
if not world.terrain[x][y] then
client.sendUpdate({"NeedsNewChunk", x, y})
coroutine.yield()
sleep()
end
end
end
end
end
-- Connects to a server.
function client.connect(computer)
print("Connecting to server...")
rednet.send(computer, "Connect")
client.connectedTo = computer
print("Loading Chunks...")
client.sendUpdate({"NeedsNewChunk", math.floor(localposx/16), math.floor(localposy/16)})
for sz=1, 2 do
client.loadChunksInitial(sz)
end
draw.game()
end
function client.onRednetMessage(param1, param2, param3, param4)
end
function client.updateBlock(chunkX, chunkY, x, y, newBlock)
for k=1, 10 do
sleep()
client.sendUpdate({"Update Block", chunkX, chunkY, x, y, newBlock})
end
end
function client.handleClient(computer)
computer = computer or myCom
client.connect(computer)
--local loadco = coroutine.create(client.loadChunksCoroutine, 2)
local blockupdate = coroutine.create(client.updateBlock, 0, 0, 1, 1, 4)
while true do
if coroutine.status(blockupdate) ~= "dead" then
coroutine.resume(blockupdate)
--print(coroutine.resume(blockupdate))
end
--coroutine.resume(loadco, 2)
--yield()
local event, p1, p2, p3, p4, p5 = os.pullEvent()
if event == "rednet_message" then
--if p1 == client.connectedTo then
local values = unserialize(p2) or {}
if values[1] == "Position Update" then
localposx, localposy = values[2], values[3]
if not world.terrain[math.floor(localposx/16)] then
world.terrain[math.floor(localposx/16)] = {}
end
if not world.terrain[math.floor(localposx/16)][math.floor(localposy/16)] then
client.sendUpdate({"NeedsNewChunk", math.floor(localposx/16), math.floor(localposy/16)})
end
elseif values[1] == "Block Updated" then
local v = values[2]
world.terrain[v[1]][v[2]][v[3]][v[4]] = v[5]
draw.game()
elseif values[1] == "Requested Chunk" then
world.terrain[values[2]][values[3]] = values[4]
end
--end
end
if event == "key" then
if p1 == keys.up then
client.sendUpdate({"Move Up"})
localposy = localposy - 1
elseif p1 == keys.down then
client.sendUpdate({"Move Down"})
localposy = localposy + 1
elseif p1 == keys.left then
client.sendUpdate({"Move Left"})
localposx = localposx - 1
elseif p1 == keys.right then
client.sendUpdate({"Move Right"})
localposx = localposx + 1
end
draw.game()
end
if event == "mouse_click" then
--local localposx, localposy = localposx - scrcenx, localposy - scrceny
local clickedx, clickedy = (p2 - scrcenx) - localposx, (p3 - scrceny) - localposy
local chunkX, chunkY = math.floor((clickedx)/16), math.floor((clickedy)/16)
local x, y = math.floor((clickedx) - (chunkX*16)) + 1, math.floor((clickedy) - (chunkY*16)) + 1
blockupdate = coroutine.create(client.updateBlock, chunkX, chunkY, x, y, 4)
--print(blockupdate)
--print(chunkX..", "..chunkY..", "..x..", "..y..", "..4)
--draw.game()
end
end
end
-- End of Functions --
draw.clear()
-- Main Loop
if not tArgs[1] then
print("Starting Server...")
server.initalizeServer()
else
client.handleClient(tonumber(tArgs[1]))
end
Edited on 06 April 2015 - 02:37 PM