This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Rooket6's profile picture

Modem API Crashes Server

Started by Rooket6, 17 June 2013 - 09:28 AM
Rooket6 #1
Posted 17 June 2013 - 11:28 AM
It seems if I recieve too many messages in a short time then the game crashes. Is there something I am doing wrong? I have 81 turtles in a 9x9 recieving that message at the same time. If it is my fault, is there anything else I can do to send that information without crashing the server? I am suprised I am not banned yet lol.

Sending Code:

    local modem = peripheral.wrap("back")
    Kill=0
    Collect=0
    Update=0
		    function waitTime(timeToWait)
		    local i = timeToWait
		    while i>=1 do
				    sleep(1)
				    write(".")
				    i = i - 1
	    end
		    print()
		    end
	
		    function sendAnUpdate()
		    if Kill == 1 then
				    modem.transmit(66, 66,"Kill is on")
		    end
		    sleep(0.1)
		    if Kill == 0 then
				    modem.transmit(66, 66,"Kill is off")
		    end
		    sleep(0.1)
		    if Collect == 1 then
				    modem.transmit(76, 76,"Collect is on")
		    end
		    sleep(0.1)
		    if Collect == 0 then
				    modem.transmit(76, 76,"Collect is off")
		    end
		    sleep(0.1)
		    if Update == 1 then
				    modem.transmit(86, 86,"Update is on")
		    end
		    sleep(0.1)
		    if Update == 0 then
				    modem.transmit(86, 86,"Update is off")
		    end
		    sleep(0.1)
		    end
		  
		    function check()
				    if rs.getInput("front")==false and Kill==0 then
				    Kill=1
				    print("Sending Kill = 1")
				    rs.setOutput("bottom", true)
				    sleep(4)
				    sendAnUpdate()
	 sleep(1)
	 sendAnUpdate()
				    sleep(1)
				    rs.setOutput("bottom", false)
				    print("Sent Kill = 1")
	 return
				    end
				    if rs.getInput("front") and Kill==1 then
				    Kill=0
				    print("Sending Kill = 0")
				    rs.setOutput("bottom", true)
				    sleep(4)
				    sendAnUpdate()
	 sleep(1)
	 sendAnUpdate()
				    sleep(1)
				    rs.setOutput("bottom", false)
				    print("Sent Kill = 0")
	 return
				    end
				    if rs.getInput("left")==false and Collect==0 then
				    Collect=1
				    print("Sending Collect = 1")
				    rs.setOutput("bottom", true)
				    sleep(4)
				    sendAnUpdate()
	 sleep(1)
	 sendAnUpdate()
				    sleep(1)
				    rs.setOutput("bottom", false)
				    print("Sent Collect = 1")
	 return
				    end
				    if rs.getInput("left") and Collect==1 then
				    Collect=0
				    print("Sending Collect = 0")
				    rs.setOutput("bottom", true)
				    sleep(4)
				    sendAnUpdate()
	 sleep(1)
	 sendAnUpdate()
				    sleep(1)
				    rs.setOutput("bottom", false)
				    print("Sent Collect = 0")
	 return
				    end
				    if rs.getInput("right")==false then
				    Update=1
				    print("Sending Update = 1")
				    rs.setOutput("bottom", true)
				    sleep(4)
				    sendAnUpdate()
	 sleep(1)
	 sendAnUpdate()
				    sleep(3)
				    rs.setOutput("bottom", false)
				    print("Sent Update = 1")
	 return
				    end
    end
	
    while true do
    check()
    sleep(0.1)
    if Update == 1 then
    write("Updating...")
    waitTime(5)
    shell.run("rm startup")
    shell.run("pastebin get FTBGLy5y startup")
    shell.run("reboot")
    end
    end

Recieving Code:

local modem = peripheral.wrap("right")
Kill = 0
Collect = 0
Update = 0
modem.open(66)
modem.open(76)
modem.open(86)
local function suckAndDrop(timesToSuck)
    local i = timesToSuck
    while i>=1 do
    turtle.suckUp()
    i = i - 1
    end
	    for i = 1,16 do
		    if turtle.getItemCount(i)>0 then
			    turtle.select(i)
			    turtle.dropDown()
		    end
	    end
end
local function kill(number)
    local i = number
    while i>=1 do
	    turtle.attackUp()
	    i = i -1
    end
end
local function checkAndSet()
if rs.getInput("right") or rs.getInput("back") or rs.getInput("bottom") then
rs.setOutput("front", true)
rs.setOutput("back", true)
rs.setOutput("right", true)
rs.setOutput("left", true)
local i = 3
while i>=1 do
local event, modemSide, senderChannel,
  replyChannel, message, senderDistance = os.pullEvent("modem_message")
print("Recieved message from channel " ..senderChannel.. ", the message was: " ..message.. ".")
if senderChannel==66 then
  Kill = message
end
if senderChannel==76 then
  Collect = message
end
if senderChannel==86 then
  Update = message
end
i = i - 1
end
while rs.getInput("bottom") do
  sleep(0)
end
rs.setOutput("front", false)
rs.setOutput("back", false)
rs.setOutput("right", false)
rs.setOutput("left", false)
while rs.getInput("back") do
sleep(0)
end
end
end
    function waitTime(timeToWait)
    local i = timeToWait
    while i>=1 do
	    sleep(1)
	    write(".")
	    i = i - 1
    end
    print()
    end

while true do
checkAndSet()
sleep(0.1)
if Update=="Update is on" then
write("Updating...")
waitTime(5)
shell.run("label set Rooket6's Grinder Turtle")
shell.run("rm startup")
shell.run("pastebin get dyDvaxmf startup")
shell.run("reboot")
end
if Kill=="Kill is on" then
kill(40)
--print("Kill is on")
end
--[[if Kill=="Kill is off" then
print("Kill is off")
end]]
if Collect=="Collect on" then
suckAndDrop(4)
--print("Collect is on")
end
--[[if Collect=="Collect is off" then
print("Collect is off")
end]]
end


Thank you in advance. :)/>/>
Lyqyd #2
Posted 17 June 2013 - 02:13 PM
Split into new topic.

You might try not spamming the ever-living hell out of the wireless network. Why do you need to send updates every tenth of a second if nothing has changed? Try slowing it down to only send updates when the redstone signal changes by using the redstone even instead of a sleep call in the main loop.
Rooket6 #3
Posted 17 June 2013 - 02:31 PM
Not using an event was my bad, I am still a pretty big noob. This code only sends updates when the red stone changes though. If I send somewhere around 10 or 20 in a minute, then it crashes. What I really would prefer to do is to stay away from the modem API, is there any other way I could still accomplish the same thing?
Bomb Bloke #4
Posted 17 June 2013 - 06:45 PM
In my experience, use of the modem API will freeze MineCraft servers at random. However, I'm not using the latest CC, and as there's quite a few mods piled into my world at the moment I've no interest in trying to upgrade them all to test later releases. People who are using later releases are still reporting much the same thing, though.

I know that using the rednet API instead won't help (I found it to be even more unstable). Throttling back the amount of messages you send helps a "little", in that it'll crash less often (my current system works anywhere from a few hours up to about a week), but the only solution currently is to ditch those APIs entirely. You can probably "get away" with using them for user-triggered messages, but any automated transmissions are a ticking timebomb.

In your case, if you have access to wireless transmitters I'd recommend using one of those instead (along with whatever you're using for redstone signal cabling to get the message to all turtles that need it). If the server is close enough, just go with the cabling.
trakos #5
Posted 25 June 2013 - 06:33 AM
Is the problem still present in the current version? I'm using tekkit lite, so I'm stuck at 1.5 version.

In my experience the deadlock bug only happens when at least two turtles will try to send the message at the very same moment. I've tested it, and having two turtles constantly spamming:


while true do
	rednet.broadcast('x')
end

will crash the server within seconds! I am not sure if they even have to be in range (or, at least have one potential message receiver that is in range of both senders). So, I'd advise the OP to check if there is anything else transmitting messages within range - in my experience there don't even have to be anything receiving to make a crash.


What I came up with is simply making them transmit at different seconds:

imagine one turtle sends messages when number of seconds modulo 2 is 0, and the other one when it is 1. Only you can't get real world time in minecraft, and I'm doing that with minecraft time fetched by os.time():

local MULTIPLIER = 5 -- the higher number, the more time frame is available for sending message, thus decreasing risk
local TIME_FACTOR = 0.05 -- dont change - how many seconds we have to wait, to increase minecraft time by 0.001

-- get the fraction part from os.time, and fill with 0s up to 3 digits
function getGameSeconds()
	local gameTime = string.sub(os.time(), 4)
	if #gameTime == 0 then gameTime = '000' end
	if #gameTime == 1 then gameTime = gameTime .. '00' end
	if #gameTime == 2 then gameTime = gameTime .. '0' end
	gameTime = gameTime + 0
	return gameTime
end

function sync(number, count)
	local gameTime = getGameSeconds()
	local waitGameTime = (count - 1 - ((gameTime / MULTIPLIER) % count) + number) * MULTIPLIER
	if gameTime + waitGameTime > 1000 then waitGameTime = (count - 1 + number) * MULTIPLIER + 1000 - gameTime end
	os.sleep(TIME_FACTOR * waitGameTime)
end

Then, suppose we have 6 turtles within range that can send message, so we make one send just after calling
sync(1,6)
, the second one after
sync(2,6)
and so on. Watch out though, making two turtles sync with the same values only makes it much worse!

The maximum time sync will wait for is MULTIPLIER * count * TIME_FACTOR, so with defaults it is 0.25 * count real time seconds, so it does add significant delay - but the reward of stability is worth much more than having to sleep for a second or two I believe ;)/>/>.

It seems to work, I haven't crashed yet using it. What do you guys think, does my attempt makes sense?
Bomb Bloke #6
Posted 25 June 2013 - 06:43 AM
I only ran the one turtle, talking to a single computer, and it still stalled the server. :(/>

Still, I'd gotten it to the point where it could last up to a week - I never tried to push things in the other direction, to have the crashes occur sooner. I think what I might do is try padding out my sending code with a few (more) sleep statements. Already shouldn't be possible for the turtle to send when the computer is doing so, but who knows what lag is capable of doing to my attempts at syncing…

If you're on the right track I might be able to avoid the stalls entirely. :)/>