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

OpenPeripheral - Showing were people are in my workshop

Started by Goof, 19 February 2014 - 07:15 AM
Goof #1
Posted 19 February 2014 - 08:15 AM
Hello!


I have been working on a workshop on a private server… I've been using openperipheral proximity sensors to see where players are compared to 9x9 rooms…

But…

If we say that i have like:


3 9x9 rooms and 1 computer with wireless modem on bottom, and sensor on top.
These computers sends all the data from the sensor( only distance from the offset, roomname, and playername ) to the monitor computer

The monitor computer receives everything, and calculates in which distance to which room is closest…
( so like if the player is 10 blocks away from sensor 1, and 9 blocks away from sensor 2, then the monitor
computer would say that the player is in the room defined by sensor 2's computer.)

So far i've made the sensors send all revelant data, from players within its range and got the monitor computer to listen to the messages…
But… how do i actually calculate ( from several modem- transmissions ) in which message keeps the closest approach?

my sensor codes
pastebin or:
Spoiler

os.loadAPI("ocs/apis/sensor")

-----
local THIS={}

THIS["Room"]="WR-Room";

local offset = {
  X = 0,
  Y = 1,
  Z = 0
}
function distance(pos)
  local xd = pos.X - offset.X
  local yd = pos.Y - offset.Y
  local zd = pos.Z - offset.Z
  return math.sqrt(
	xd*xd+yd*yd+zd*zd
  )
end
local modem = peripheral.wrap("bottom")
modem.open(25565)
local Current_username_=false
local playerDist={}
local proximity = sensor.wrap("top")
while true do
  local signal = false
  local targets = proximity.getTargets()
  if targets then
	for player, infotable in pairs(targets) do
	  if infotable.IsPlayer then
		Current_username_=player
		playerDist[player]={}
		term.setCursorPos(1,1)term.clearLine() term.setCursorPos(1,1)print("Current User: "..player)
		local targetDetail=proximity.getTargetDetails(player)
		if targetDetail then
		  for info, data in pairs(targetDetail) do
			if type(data)=='table' then
			  if tostring(info)=="Position" then
				if not data then else
				  term.setCursorPos(1,2)
				  term.clearLine()
				  term.setCursorPos(1,2)
				  playerDist[Current_username_]={["room"]=THIS["Room"];["name"]=Current_username_;["distance"]=tostring(distance(data))}
				  print("Distance: "..playerDist[Current_username_]["distance"].." blocks")
				  modem.transmit(25565,25565,textutils.serialize(playerDist))
				end
			  end
			else

			end
		  end
		end
	  end
	end
  end
  sleep(0)
end

and my current monitorcomputer code: i know this is not on a monitor.. but i can't since my friends minecraft crashes, caused by monitor.screen.drawWitdh….. (yup… videocard outdated)
pastebin or:

Spoiler

--- Monitor --- Showing were players are in the workshop.

modem = peripheral.wrap("left")

modem.open(25565)-- listening
local roomData={
	--[[
	[player_name]={
		[room]=distance
	}


	--]]
}

local test = {
	[1]={1;5;7;2;}

}
print(math.min(test[1][1],test[1][2],test[1][3]))

while true do
	local event, side, senderChannel,receiverChannel,message, distance = os.pullEvent("modem_message")
	if senderChannel==25565 then
		local playerdat=textutils.unserialize(message)
		for k,v in pairs(playerdat) do
			local dist = v["distance"]
			local room = v["room"]
			roomData[k]={[room]=dist;};
		end
	end
	for k,v in pairs(roomData) do
		for i,j in pairs(v) do
			local smallestDist=math.min(j)
			print(tostring(smallestDist))
			for k,v in pairs(roomData) do

			end
			roomData[k]["exactRoom"]=realRoom
		end
	end
end

I've been trying to use math.min… but it doesnt support tables.. so i dont know how to do this



Thanks in advance….

I hope I'll be able to solve this
Edited on 19 February 2014 - 09:33 AM
CometWolf #2
Posted 19 February 2014 - 09:44 AM
and my current monitorcomputer code: i know this is not on a monitor.. but i can't since my friends minecraft crashes, caused by monitor.screen.drawWitdh….. (yup… videocard outdated)
Is this even a function? I've never even heard of a table within the monitor api called screen.

I've been trying to use math.min… but it doesnt support tables.. so i dont know how to do this
math.min with tables works just fine, hell the test code you included in your script even works…

Now then, as for your actual problem…

local roomData={
	    --[[
	    [player_name]={
			    [room]=distance
	    }

	    --]]
}
You're defining your table all wrong. "–[[]]–" means it's a string, so what you've got here is a table called roomData, containing a single string.
This is what it should look like

local roomData = {
  player_name = {
    room = distance
  }
}
This code however, is pointless, as you are defining it prior to even defining the distance or player_name variables. It might aswell just be local roomData = {}.


			    local playerdat=textutils.unserialize(message)
			    for k,v in pairs(playerdat) do
					    roomData[k] = {} --define the playername index
					    roomData[k].dist = v.distance --save the distance
					    roomData[k].room = v.room --save the room
			    end
	    end

Your sender code is so derp i don't even wanna get started on that. Please go read up on LUA formatting and coding conventions. Don't use a pairs loop when you know the name of the indexes you want, it makes no sense!



if not data then else
Just… what?
Bomb Bloke #3
Posted 19 February 2014 - 09:46 AM
math.min() reports the lowest value in a list of values. math.min(3,5) will return 3, for eg - if you only pass it one value (eg math.min(j)), then it'll only return that one value (eg j).

While it is possible to indirectly pass a numerically indexed table to math.min() by use of unpack(), your table isn't suitable for that.

Anyway, you're specifically turning the value your "distance()" function returns into a string before you send it (why?), so you'll have trouble treating it as a number at the other end. I suggest removing the "tostring()" call. Well, all of them, actually.

You could then rewrite this:

        for k,v in pairs(roomData) do
                for i,j in pairs(v) do
                        local smallestDist=math.min(j)
                        print(tostring(smallestDist))
                        for k,v in pairs(roomData) do

                        end
                        roomData[k]["exactRoom"]=realRoom
                end
        end

… as something like this:

        for k,v in pairs(roomData) do
                local smallestDist = 200  -- Preset our "target" to something larger then any detector will return.
                for i,j in pairs(v) do
                        if j < smallestDist then            -- If this detector is closer then our "target",
				smallestDist = j            -- ... then make this the new target...      
				roomData[k]["exactRoom"]=i  -- ... and update the "closest room".
                        end
                end
                print(roomData[k]["exactRoom"].." seems closest for player "..k.." with a distance of "..smallestDist..".")
        end

Edit: Ninja'd. But:

You're defining your table all wrong. "–[[]]–" means it's a string, so what you've got here is a table called roomData, containing a single string.
Erm, you might be thinking of "[[]]". He's used a block comment there.

I've got a hunch his script is near-working, but I'm up too far past my bedtime to say for sure.
Edited on 19 February 2014 - 08:51 AM
Goof #4
Posted 19 February 2014 - 09:57 AM
Well I'll stick with Bomb Bloke's answer for now…

Anyway, you're specifically turning the value your "distance()" function returns into a string before you send it (why?), so you'll have trouble treating it as a number at the other end. I suggest removing the "tostring()" call. Well, all of them, actually.
Removed all tostrings

		for k,v in pairs(roomData) do
				for i,j in pairs(v) do
						local smallestDist=math.min(j)
						print(tostring(smallestDist))
						for k,v in pairs(roomData) do

						end
						roomData[k]["exactRoom"]=realRoom
				end
		end

… as something like this:

		for k,v in pairs(roomData) do
				local smallestDist = 200  -- Preset our "target" to something larger then any detector will return.
				for i,j in pairs(v) do
						if j < smallestDist then			-- If this detector is closer then our "target",
				smallestDist = j			-- ... then make this the new target...	  
				roomData[k]["exactRoom"]=i  -- ... and update the "closest room".
						end
				end
				print(roomData[k]["exactRoom"].." seems closest for player "..k.." with a distance of "..smallestDist..".")
		end

Yeah… That might work.. im gonna test…


and:

Edit: Ninja'd. But:

You're defining your table all wrong. "–[[]]–" means it's a string, so what you've got here is a table called roomData, containing a single string.
Erm, you might be thinking of "[[]]". He's used a block comment there.

I've got a hunch his script is near-working, but I'm up too far past my bedtime to say for sure.

Well… yeah.. i made a block comment, just so i could see how it should be formatted etc……
And im more familar with Bomb bloke's code as for now…

Thanks everyone..

I'll edit this with the result
Goof #5
Posted 19 February 2014 - 10:31 AM
Hmmm.. somehow when multiple players enters, it crashes… ( the sensor computer doesnt send the "distance" and room of the new players..


why?


monitor computer code :
Spoiler

--- Monitor --- Showing were players are in the workshop.

modem = peripheral.wrap("back")

modem.open(25565)-- listening
local roomData={
	--[[
	[player_name]={
		[room]=distance
	}


	--]]
}
local storedPlayers={
  latest=0
  --[[
  [player]={
    y=0
  }
  ]]
}
local firstY=0
local oldK=false
while true do
  local event, side, senderChannel,receiverChannel,message, distance = os.pullEvent("modem_message")
  --print("Received")
  if senderChannel==25565 then
    local playerdat=textutils.unserialize(message)
    for k,v in pairs(playerdat) do
      local dist = v["distance"]
      local room = v["room"]
      roomData[k]={}
      roomData[k]={[room]=dist;};
    end
  end
  for k,v in pairs(roomData) do
    local MAXDISTANCE=201
    local smallestDist=200  -- Preset our "target" to something larger then any detector will return.
    for i,j in pairs(v) do
      if j < smallestDist and j < MAXDISTANCE then            -- If this detector is closer then our "target",
        smallestDist = j            -- ... then make this the new target...      
        roomData[k]["exactRoom"]=i  -- ... and update the "closest room".
        --roomData[k]["YPos"]=curY+1
      end
    end
    function tr()
      for i,j in pairs(storedPlayers) do
        if k == i then
          term.setCursorPos(1,j.y)
          return true
        end
      end
      return false
    end
    function _maxStored()
      local smallestDist2 = 0  -- Preset our "target" to something larger then any detector will return.
      for k,v in pairs(storedPlayers) do
        if v > smallestDist2 then            -- If this detector is closer then our "target",
          smallestDist2 = j            -- ... then make this the new target...      
        end
      end
      return smallestDist2+1
    end
    if not tr() then
      storedPlayers[k]={y=_maxStored()}
    else
      term.setCursorPos(1,storedPlayers[k].y)
      term.clearLine()
      print(roomData[k]["exactRoom"].." seems closest for "..k..". ("..math.floor(smallestDist)..")")
    end
  end
end


sensor code… ( placed debugging strings… )
Spoiler

os.loadAPI("ocs/apis/sensor")

----- 
local THIS={}

THIS["Room"]="WR-Room";

local offset = {
  X = 0,
  Y = 1,
  Z = 0
}
function distance(pos)
  local xd = pos.X - offset.X
  local yd = pos.Y - offset.Y
  local zd = pos.Z - offset.Z
  return math.sqrt(
    xd*xd+yd*yd+zd*zd
  )
end
local modem = peripheral.wrap("bottom")
modem.open(25565)

local Current_username_=false
local playerDist={}
local proximity = sensor.wrap("top")
while true do
  local signal = false
  local targets = proximity.getTargets()
  if targets then
    for player, infotable in pairs(targets) do
      if infotable.IsPlayer then
        term.setCursorPos(1,4)
        print(player)
        Current_username_=player
        playerDist[player]={}
        term.setCursorPos(1,1)term.clearLine() term.setCursorPos(1,1)print("Current User: "..player)
        local targetDetail=proximity.getTargetDetails(player)
        if not targetDetail then else
          term.setCursorPos(1,5)
          print("true1")
          for info, data in pairs(targetDetail) do
            if type(data)=='table' then
              term.setCursorPos(1,6)
              print("true2")
              if tostring(info)=="Position" then
                term.setCursorPos(1,7)
                print("true3")
                if data then
                  term.setCursorPos(1,8)
                  print("true4")
                  term.setCursorPos(1,2)
                  term.clearLine()
                  term.setCursorPos(1,2)
                  playerDist[Current_username_]={["room"]=THIS["Room"];["name"]=Current_username_;["distance"]=distance(data)}
                  print("Distance: "..playerDist[Current_username_]["distance"].." blocks")
                  modem.transmit(25565,25565,textutils.serialize(playerDist))
                end
              end
            else

            end
          end
        end
      end
    end
  end
  sleep(0)
end
Bomb Bloke #6
Posted 19 February 2014 - 10:41 AM
Sorry, my brain's shut down for the night. All I'll say for now is that I had no intention for that code I gave you to be written in your script more then once - in place of the other segment I quoted.

If your script is "crashing", quote the exact error. If it's doing something else, describe that behaviour instead.
Goof #7
Posted 19 February 2014 - 10:44 AM
Welll I figured out that when two players are near / when its sending the table ( sensor ) then it seems like only my name table ( mikkel809h ) is a table with distance room etc…
It looks like it doesn't fill in the distances and room for more than one player….


hmmm




EDIT:

Found Out:!

Nevermind..
Code:
monitor:
Spoiler

--- Monitor --- Showing were players are in the workshop.

modem = peripheral.wrap("back")

modem.open(25565)-- listening
local roomData={
	--[[
	[player_name]={
		[room]=distance
	}


	--]]
}
local storedPlayers={
  --[[
  [player]={
    y=0
  }
  ]]
}
local firstY=0
local oldK=false
while true do
  local event, side, senderChannel,receiverChannel,message, distance = os.pullEvent("modem_message")
  --print(message)
  if senderChannel==25565 then
    local playerdat=textutils.unserialize(message)
    for k,v in pairs(playerdat) do
      local dist = tonumber(v["distance"])
      local room = tostring(v["room"])
      roomData[k]={}
      roomData[k]={[room]=dist;};
    end
  end
  for k,v in pairs(roomData) do
    local MAXDISTANCE=201
    local smallestDist=200  -- Preset our "target" to something larger then any detector will return.
    for i,j in pairs(v) do
      if j < smallestDist and j < MAXDISTANCE then            -- If this detector is closer then our "target",
        smallestDist = j            -- ... then make this the new target...      
        roomData[k]["exactRoom"]=i  -- ... and update the "closest room".
        --roomData[k]["YPos"]=curY+1
      end
    end
    function tr()
      for i,j in pairs(storedPlayers) do
        if k == i then
          term.setCursorPos(1,j.y)
          return true
        end
      end
      return false
    end
    function _maxStored()
      local smallestDist2 = 0  -- Preset our "target" to something larger then any detector will return.
      for k,v in pairs(storedPlayers) do
        term.setCursorPos(1,16)
        --print(k.." - "..textutils.serialize(v))
        if v["y"] > smallestDist2 then            -- If this detector is closer then our "target",
          smallestDist2 = v["y"]            -- ... then make this the new target...      
        end
      end
      return smallestDist2+1
    end
    if not tr() then
      storedPlayers[k]={y=_maxStored()}
    else
    end
      term.setCursorPos(1,storedPlayers[k].y)
      term.clearLine()
      print(tostring(roomData[k]["exactRoom"]).." seems closest for "..tostring(k)..". ("..tostring(math.floor(smallestDist))..")")
  end
end

Sensors… ( can now accept multiple sensors :o/> )
Spoiler

os.loadAPI("ocs/apis/sensor")

----- 
local THIS={}

THIS["Room"]="WR-Room";

local offset = {
  X = 0,
  Y = 1,
  Z = 0
}
function distance(pos)
  local xd = pos.X - offset.X
  local yd = pos.Y - offset.Y
  local zd = pos.Z - offset.Z
  return math.sqrt(
    xd*xd+yd*yd+zd*zd
  )
end
local modem = peripheral.wrap("bottom")
modem.open(25565)

local Current_username_=false
local playerDist={}
local proximity = sensor.wrap("top")
while true do
  local signal = false
  local targets = proximity.getTargets()
  if targets then
    for player, infotable in pairs(targets) do
      if infotable.IsPlayer then
        term.setCursorPos(1,4)
        print(player)
        Current_username_=player
        playerDist[player]={}
        term.setCursorPos(1,1)term.clearLine() term.setCursorPos(1,1)print("Current User: "..player)
        local targetDetail=proximity.getTargetDetails(player)
        if not targetDetail then else
          term.setCursorPos(1,5)
          print("true1")
          for info, data in pairs(targetDetail) do
            if type(data)=='table' then
              term.setCursorPos(1,6)
              print("true2")
              if tostring(info)=="Position" then
                term.setCursorPos(1,7)
                print("true3")
                if data then
                  term.setCursorPos(1,8)
                  print("true4")
                  term.setCursorPos(1,2)
                  term.clearLine()
                  term.setCursorPos(1,2)
                  playerDist[Current_username_]={["room"]=THIS["Room"];["name"]=Current_username_;["distance"]=distance(data)}
                  print("Distance: "..playerDist[Current_username_]["distance"].." blocks")
                  modem.transmit(25565,25565,textutils.serialize(playerDist))
                end
              end
            else

            end
          end
        end
      end
    end
  end
  sleep(0)
end
Edited on 19 February 2014 - 10:05 AM
CometWolf #8
Posted 19 February 2014 - 11:39 AM
Right, my bad about the comments lol. Anyways, i cleaned up your code so it's a bit easier to follow.

Quick note, you are not using a openP sensor! You are using openCCSensors.

os.loadAPI("ocs/apis/sensor")

-----
local sensRoom = "WR-Room" --sensor room, why make a table with a single value...

local offset = {
  X = 0,
  Y = 1,
  Z = 0
}
function distance(pos)
  local xd = pos.X - offset.X
  local yd = pos.Y - offset.Y
  local zd = pos.Z - offset.Z
  return math.sqrt(xd*xd+yd*yd+zd*zd)
end
local modem = peripheral.wrap("bottom")
modem.open(25565)

local proximity = sensor.wrap("top")
while true do
  local signal --Is this even used?
  local targets = proximity.getTargets()
  if targets then
	for player, infotable in pairs(targets) do
	  if infotable.IsPlayer then
		term.setCursorPos(1,4)
		print(player)
		term.setCursorPos(1,1)
		term.clearLine()
		term.setCursorPos(1,1)
		print("Current User: "..player)
		local targetDetail = proximity.getTargetDetails(player)
		if not targetDetail then else --why on earth are you doing these!?
		  term.setCursorPos(1,5)
		  print("true1")
		  print("Distance: "..distance(targetDetail.Position).." blocks")
		  modem.transmit(25565,25565,textutils.serialize({
			room = sensRoom,
			name = player,
			["distance"] = distance(targetDetail.Position)
		  })
		end
	  end
	end
  end
  sleep(0.1)
end


As for the problem you are currently experiencing, does it actually print your name, but not the other guy's?
Looking over my old sensor code(11 months old), ocs sensors just return player as the name of players, to get the username you need to check details.Username. I do however not know wether this has been changed or not since then.
Edited on 19 February 2014 - 10:49 AM