aboutsummaryrefslogtreecommitdiff
path: root/src/serverlist.cpp
Commit message (Expand)AuthorAge
* Remove ugly curl struct pointer from jsonFetchValue signaturesapier2014-06-19
* Remove a lot of superfluous ifndef USE_CURL checkssapier2014-06-19
* Remove liquid_finite and weatherproller2014-04-18
* Fix wrong named masterserver announce variableproller2014-01-07
* Send long announce as POST, show OS in useragentproller2014-01-07
* Use httpfetch_async in serverlist announce codeKahrl2013-12-13
* Rename names -> can_see_far_names in announceproller2013-12-03
* Remove link to #, add unlimited_player_transfer_distance to announceproller2013-12-03
* Correct useragent in http queriesproller2013-11-06
* Masterserver show privs and js autoloadproller2013-11-04
* Masterserver updateproller2013-10-18
* Show git hash in version string at top left corner of windowKahrl2013-09-28
* Dont write directly to files but rather write and copy a tmp filePilzAdam2013-08-13
* More info in serverlistproller2013-08-03
* Masterserver mods announse, ipv6, better curl errorsproller2013-07-13
* Replace C++ mainmenu by formspec powered onesapier2013-07-02
* Fix favorite Server List on WindowsSfan52013-05-04
* Fix serverlist on -DRUN_IN_PLACE=0 (use path_user instead of path_share)Zeg92013-04-25
* Masterserver: report gameid, uptime, cosmetic fixes on server web pageproller2013-03-30
* Add one more curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);Ilya Zhuravlev2013-03-03
* Fix "longjmp causes uninitialized stack frame" (serverlist.cpp)Ilya Zhuravlev2013-03-01
* Update Copyright YearsSfan52013-02-24
* Change Minetest-c55 to MinetestPilzAdam2013-02-24
* new auto masterserverproller2013-02-22
* Add a list of servers to the "Multiplayer" tabJeija2013-01-21
>247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708




local mod_name = minetest.get_current_modname()

local mod_version = "2.13"

local function log(level, message)
    minetest.log(level, ('[%s] %s'):format(mod_name, message))
end

log('action', 'CSM cs_waypoints '..mod_version..' loading...')

minetest.display_chat_message("CSM cs_waypoints "..mod_version.." loading...")

local mod_storage = minetest.get_mod_storage()


local search_delta_default = 10

local daydelay_default = 5
local bouncedelay_default = 10

--
--
-- local functions
--
--

local function load_waypoints()
    if string.find(mod_storage:get_string('waypoints'), 'return') then
        return minetest.deserialize(mod_storage:get_string('waypoints'))
    else
        return {}
    end
end

local function load_waypoints_stack()
    if string.find(mod_storage:get_string('waypoints_stack'), 'return nil') then
       return {}
    end
    if string.find(mod_storage:get_string('waypoints_stack'), 'return') then
        return minetest.deserialize(mod_storage:get_string('waypoints_stack'))
    else
        return {}
    end
end

local waypoints = load_waypoints()


local function safe(func)
    -- wrap a function w/ logic to avoid crashing the game
    local f = function(...)
        local status, out = pcall(func, ...)
        if status then
            return out
        else
            log('warning', 'Error (func):  ' .. out)
            return nil
        end
    end
    return f
end


local function round(x)
   return math.floor(x+0.5)
end


local function pairsByKeys(t, f)
    local a = {}
    for n in pairs(t) do
        table.insert(a, n)
    end
    table.sort(a, f)
    local i = 0
    return function()
        i = i + 1
        if a[i] == nil then
            return nil
        else
            return a[i], t[a[i]]
        end
    end
end


local function lc_cmp(a, b)
    return a:lower() < b:lower()
end


local function tostring_point(point)
   if not point then 
      return " - - - "
   end 
   return ('%i %i %i'):format(round(point.x), round(point.y), round(point.z))
end




local function teleport_to(position_name)
   local wpname = position_name
   local waypoint = waypoints[wpname]
   if waypoint ~= nil then
      minetest.run_server_chatcommand('teleport', tostring_point(waypoint))
   else
      minetest.display_chat_message(('waypoint "%s" not found.'):format(wpname))
   end
   return true
end

local function show_pos(position_name)
   local wpname = position_name
   local waypoint = waypoints[wpname]
   local rg = ""
   if waypoint ~= nil then
      rg = wpname .. ": " .. tostring_point(waypoint)
   else
      rg = ('waypoint "%s" not found.'):format(wpname)
   end
   return true,rg
end



local function stack_push()
   local point = minetest.localplayer:get_pos()
   local wp_stack = load_waypoints_stack()
   local count = #wp_stack +1
   wp_stack[count] = point
   mod_storage:set_string('waypoints_stack', minetest.serialize(wp_stack))
end

local function stack_pop()
   local wp_stack = load_waypoints_stack()
   local count = 0
   if nil ~= wp_stack then count = #wp_stack end
   if count<1 then
      minetest.display_chat_message('stack empty - no teleporting')
      return
   end
   minetest.run_server_chatcommand('teleport', tostring_point(wp_stack[count]))
   wp_stack[count] = nil
   mod_storage:set_string('waypoints_stack', minetest.serialize(wp_stack))
   return true   
end

local function stack_use()
   local wp_stack = load_waypoints_stack()
   count = 0
   if nil ~= wp_stack then count = #wp_stack end
   if count<1 then
      minetest.display_chat_message('stack empty - no teleporting')
      return
   end
   minetest.run_server_chatcommand('teleport', tostring_point(wp_stack[count]))
   return true   
end

local function stack_exch()
   local wp_stack = load_waypoints_stack()
   count = 0
   if nil ~= wp_stack then count = #wp_stack end
   if count<2 then
      minetest.display_chat_message('less than 2 entries - no change')
      return
   end
   local exch        = wp_stack[count]
   wp_stack[count]   = wp_stack[count-1]
   wp_stack[count-1] = exch
   mod_storage:set_string('waypoints_stack', minetest.serialize(wp_stack))
   return true   
end


local function stack_show()
   local wp_stack = load_waypoints_stack()
   count = 0
   if nil ~= wp_stack then count = #wp_stack end
   if count<1 then
      minetest.display_chat_message('stack empty')
      return true
   end
   output = ""
   for i = count,1,-1 do
      output = output .. tostring(i) .. "  " ..  tostring_point(wp_stack[i]).."\n"
   end
   return true ,output
end

local function stack_clear()
   mod_storage:set_string('waypoints_stack', minetest.serialize(nil))
end

local function  stack_search(d)   
   local delta = d
   if delta then       delta = tonumber(delta) end
   if nil == delta then delta = search_delta_default  end 
   if delta < 0 then delta = 0 end
   
   here = minetest.localplayer:get_pos()
   minetest.display_chat_message(
                ('%s : %s'):format("current position", tostring_point(here))
            )
   for name,pos in pairsByKeys(waypoints, lc_cmp) do
      if math.abs(here.y-pos.y) <= delta then
	 if math.abs(here.x-pos.x) <= delta then
	    if math.abs(here.z-pos.z) <= delta then
	       minetest.display_chat_message(
		     ('%s -> %s'):format(name, tostring_point(pos)))
	    end
	 end
      end
   end
   return true
end

local function position_shift(p)   
   local param = p
   if not p then return end
   while p:sub(1,1) == " " and p:len()> 3 do
      p = p:sub(2,99)
   end
   if p:len()<3 then return end
   direction = p:sub(1,1)
   d = ""
   if direction == "x" or direction == "X" then d = "x" end 
   if direction == "y" or direction == "Y" then d = "y" end 
   if direction == "z" or direction == "Z" then d = "z" end 
   if d == "" then return end

   here = minetest.localplayer:get_pos()

   distance = tonumber(p:sub(2,8))
   if not distance then return end
   if distance == 0 then return end
   
   here[d] = here[d] + distance 
   -- here.y  = here.y  - 1        -- correction

   minetest.run_server_chatcommand('teleport', tostring_point(here))

end

-- new shift with more than one possible shift coordinate
-- only the last value for one coordinate is used
local function position_shift2(p)   
   if not p then return end

   local param = p:split(" ")

   local shift = {}
   shift.x = 0
   shift.y = 0
   shift.z = 0

   local vp = 1
   while (vp+1 <= #param )
   do
      local direction = param[vp]
      d = ""
      if direction == "x" or direction == "X" then d = "x" end 
      if direction == "y" or direction == "Y" then d = "y" end 
      if direction == "z" or direction == "Z" then d = "z" end 
      if d ~= "" then 
	 distance = tonumber(param[vp+1])
	 if not distance then 
	    distance = 0
	 end
	 shift[direction] = distance
      end
      vp = vp+2
   end

   if shift.x == 0 and shift.y == 0 and shift.z == 0 then
      return
   end

   local here = minetest.localplayer:get_pos()

   here.x = here.x+shift.x
   here.y = here.y+shift.y
   here.z = here.z+shift.z

   -- here.y  = here.y  - 1        -- correction

   minetest.run_server_chatcommand('teleport', tostring_point(here))

end


local function calc_distance(wp)
   local wpname = wp
   local waypoint = waypoints[wpname]
   local rg = ""
   if waypoint == nil then
      rg = ('waypoint "%s" not found.'):format(wp)
   else
      here = minetest.localplayer:get_pos()
      dx = math.abs(here.x-waypoint.x)
      dy = math.abs(here.y-waypoint.y)
      dz = math.abs(here.z-waypoint.z)
      l1 = "x: " .. tostring(round(100*dx)/100) .. "   y: " 
	 .. tostring(round(100*dy)/100) .. "   z: " 
	 .. tostring(round(100*dz)/100)
      delta_hor = math.floor(math.sqrt(dx*dx+dz*dz)*100)/100
      delta_3d =  math.floor(math.sqrt(dx*dx+dy*dy+dz*dz)*100)/100
      l2 = "distance: " .. tostring(delta_3d) 
	 .. "    horizontal distance: " .. tostring(delta_hor) 
      rg = l1 .. "\n" .. l2
   end

   return true,rg
end


local function teleport_day_back(x,y,z)
   minetest.run_server_chatcommand('teleport', 
				   string.format("%f %f %f",x,y+1,z)
				)
   return
end


local function teleport_day(params)
   local daypos = mod_storage:get_string('daypos')
   local daydelay = mod_storage:get_string('daydelay')
   daypos = minetest.deserialize(daypos) 
   daydelay = (daydelay and tonumber(minetest.deserialize(daydelay))) or 
               daydelay_default

   if not params or
      params == "" 
   
   then
      -- no parameter - execute the function
      if not daypos  then
	 minetest.display_chat_message("no saved position")	 
	 return
      end
      local pstr = tostring_point(daypos)
      minetest.display_chat_message("position "..pstr)
      minetest.run_server_chatcommand('teleport', pstr)
      local point = minetest.localplayer:get_pos()
      minetest.after(daydelay,teleport_day_back,point.x,point.y,point.z)
      return
   end

   if params == "show" then
      minetest.display_chat_message("position: "..tostring_point(daypos)..
				    "   delay:"..daydelay)
      return
   end
   if params == "setpos" then
      local point = minetest.localplayer:get_pos()
      local pstr = tostring_point(point)
      minetest.display_chat_message("position "..pstr)
      mod_storage:set_string('daypos', minetest.serialize(point))
      minetest.display_chat_message("position saved")
      return
   end
   local sdp = string.find(params,"setdelay ",1,false)
   if sdp and sdp == 1 then
      local newtime = tonumber(params:sub(10,16))
      if newtime and newtime>0 then
	 mod_storage:set_string('daydelay', minetest.serialize(newtime))
	 minetest.display_chat_message("delay saved")	 
      end
      return
   end
   -- wrong parameters - what now?
   return
end





local function teleport_bounce(params)

   if not params or
      params == "" 
   
   then
      -- no parameter - return
      minetest.display_chat_message("no waypoint given")	 
      return
   end

   local bouncedelay = mod_storage:get_string('bouncedelay')
   bouncedelay = (bouncedelay and tonumber(minetest.deserialize(bouncedelay))) or 
                bouncedelay_default
   
   local sdp = string.find(params,"setdelay",1,false)
   if sdp and sdp == 1 then
      local newtime = tonumber(params:sub(10,16))

      if newtime and newtime>0 then
	 mod_storage:set_string('bouncedelay', minetest.serialize(newtime))
	 minetest.display_chat_message("delay saved")	 
      else
	 minetest.display_chat_message("delay: "..bouncedelay)	 	 
      end
      return
   end
      
   local bouncepos = params
   local bouncetarget = waypoints[bouncepos]
   if not bouncetarget then
      minetest.display_chat_message("unknown waypoint")	 
      return
   end
   
   local pstr = tostring_point(bouncetarget)
   local point = minetest.localplayer:get_pos()
   minetest.after(bouncedelay,teleport_day_back,point.x,point.y,point.z)
   minetest.display_chat_message("position "..pstr)
   minetest.run_server_chatcommand('teleport', pstr)
   return
end


local function wp_export(param)
   local wpl = load_waypoints()
   if not wpl then return end
   local list = ""
   for k,p in pairsByKeys(wpl,lc_cmp) do
      if param == "" or string.find(k,param,1,true) then
	 local line = "("..p.x..","..p.y..","..p.y..")  name = "..k.."\n"
	 list = list .. line
      end
   end
   minetest.display_chat_message(list)
         minetest.show_formspec("cs_waypoints:export",
        "size[15,12]" ..
        "label[3.5,0;Waypoint List]"..
        "textarea[0.3,1;15,11;note;;".. list .."]"..
        "button_exit[4.5,11.2;1.4,1;e;Close]")

   return
end


--
--
-- chat commands
--
--


minetest.register_chatcommand('wp_set', {
    params = '<name>',
    description = 'set a waypoint',
    func = safe(function(param)
        waypoints = load_waypoints()
        local point = minetest.localplayer:get_pos()
        if waypoints[param] then
	   minetest.display_chat_message(
		 ('waypoint "%s" not saved: already set'):format(param)
				      )
	   return
	end
	   
        waypoints[param] = point
        mod_storage:set_string('waypoints', minetest.serialize(waypoints))

        minetest.display_chat_message(
            ('set waypoint "%s" to "%s"'):format(param, tostring_point(point))
        )
    end),
})


minetest.register_chatcommand('wp_unset', {
    params = '<name>',
    description = 'remove a waypoint',
    func = safe(function(param)
        waypoints = load_waypoints()
        waypoints[param] = nil
        mod_storage:set_string('waypoints', minetest.serialize(waypoints))

        minetest.display_chat_message(
            ('removed waypoint "%s"'):format(param)
        )
    end),
})


minetest.register_chatcommand('wp_list', {
    params = '',
    description = 'lists waypoints',
    func = safe(function(_)
        for name, point in pairsByKeys(waypoints, lc_cmp) do
            minetest.display_chat_message(
                ('%s -> %s'):format(name, tostring_point(point))
            )
        end
    end),
})


minetest.register_chatcommand('tw', {
	params = '<waypoint>',
	description = 'teleport to a waypoint',
	func = safe(function(param)
		       safe(teleport_to(param))
		    end),
     }
  )


minetest.register_chatcommand('tw_push', {
	params = '<waypoint>',
	description = 'teleport to a waypoint and save old position',
	func = safe(function(param)
		       stack_push()
		       safe(teleport_to(param))
		    end),
     }
  )

minetest.register_chatcommand('wp_push', {
	params = '<position/player>',
	description = 'teleport to a position/player and save old position',
	func = safe(function(param)
		       stack_push()
		       minetest.run_server_chatcommand('teleport', param)
		    end),
      }
   )

minetest.register_chatcommand('tw_pop', {
	params = '',
	description = 'return to the last saved position',
	func = stack_pop,
     }
  )

minetest.register_chatcommand('wp_pop', {
	params = '',
	description = 'return to the last saved position',
	func = stack_pop,
     }
  )

minetest.register_chatcommand('tw_use', {
	params = '',
	description = "use the last saved position but don't remove it",
	func = stack_use,
     }
  )

minetest.register_chatcommand('wp_use', {
	params = '',
	description = "use the last saved position but don't remove it",
	func = stack_use,
     }
  )

minetest.register_chatcommand('tw_exch', {
	params = '',
	description = 'exchange the top two stack entried',
	func = stack_exch,
     }
  )

minetest.register_chatcommand('wp_exch', {
	params = '',
	description = 'exchange the top two stack entried',
	func = stack_exch,
     }
  )
minetest.register_chatcommand('wp_stack', {
	params = '',
	description = 'shows the stack content',
	func = stack_show,
     }
  )

minetest.register_chatcommand('wp_stack_clear', {
	params = '',
	description = 'clears the position stack',
	func = stack_clear,
     }
  )


minetest.register_chatcommand('wp_search', {
	params = '(<delta>)',
	description = 'search a waypoint near the current position',
	func = stack_search,
     }
  )


minetest.register_chatcommand('wp_shift', {
	params = '<axis> <distance>',
	description = '"shift" the player along the given axis and add the given number',
	func = position_shift2,
     }
  )


minetest.register_chatcommand('wp_dist', {
	params = '<waypoint>',
	description = 'calculate the distance to a given waypoint',
	func = calc_distance,
     }
  )
        

minetest.register_chatcommand('wp_show', {
	params = '<waypoint>',
	description = 'show the coordinates of a given waypoint',
	func = show_pos,
     }
  )


minetest.register_chatcommand('tp', {
	params = '<position/player>',
	description = 'shortcut for /teleport',
	func = safe(function(param)
		       safe(minetest.run_server_chatcommand('teleport',param ))
		    end),
     }
  )
        

--  wp_grep    written by erstazi (player at Linux-Forks.de )
minetest.register_chatcommand('wp_grep', {
    params = '<name>',
    description = 'lists matching waypoints',
    func = safe(function(param)
        local wpname = param
        local count = 0
        for name, point in pairsByKeys(waypoints, lc_cmp) do
            if string.find(name, wpname) then
                count = count + 1
                minetest.display_chat_message(
                    ('%s -> %s'):format(name, tostring_point(point))
                )
            end
        end

        if count == 0 then
            minetest.display_chat_message(('waypoint "%s" not found.'):format(wpname))
        end
    end),
})

--  wp_fgrep   derived from wp_grep by erstazi
minetest.register_chatcommand('wp_fgrep', {
    params = '<name>',
    description = 'lists matching waypoints',
    func = safe(function(param)
        local wpname = param
        local count = 0
        for name, point in pairsByKeys(waypoints, lc_cmp) do
            if string.find(name, wpname,1,true) then
                count = count + 1
                minetest.display_chat_message(
                    ('%s -> %s'):format(name, tostring_point(point))
                )
            end
        end

        if count == 0 then
            minetest.display_chat_message(('waypoint "%s" not found.'):format(wpname))
        end
    end),
})


minetest.register_chatcommand('day', {
	params = '[show|setpos|setdelay <number>]',
	description = 'teleports to the day button and return after a few seconds ',
	func = teleport_day,
     }
  )


-- bounce  name idea by Maverick2797 on 2021-05-20
-- jump to a waypoint and 'bounce' back to the start point after a delay
minetest.register_chatcommand('bounce', {
	params = '[<waypoint>|setdelay [<number>]]',
	description = 'teleports to the given waypoint and returns after a few seconds ',
	func = teleport_bounce,
     }
  )

minetest.register_chatcommand('wp_export', {
	params = '[<name part>]',
	description = 'Export all waypoints as list',
	func = wp_export,
     }
  )



log('action', 'CSM cs_waypoints '..mod_version..' loaded')
minetest.display_chat_message("CSM cs_waypoints "..mod_version.." loaded")