Cuberite Forum
Redirect Player - Printable Version

+- Cuberite Forum (https://forum.cuberite.org)
+-- Forum: Plugins (https://forum.cuberite.org/forum-1.html)
+--- Forum: Plugin Discussion (https://forum.cuberite.org/forum-8.html)
+--- Thread: Redirect Player (/thread-2193.html)



Redirect Player - Nether Mc - 10-30-2015

Hello,

I just started developing plugins for Cuberite, but now I'm stuck at two points:

1. Redirect a Player to another Server

How to redirect a player to another Server; I added a rightclick hook and compared the coordinates with a list of signs, but how to continue?

2. Get a cPlayer or cWorld class

How to "link" a cPlayer class to a Player? I know how to use it if I get one through a hook, but if I need a second one of another player, I don't know how to get it Sad

I'd be happy if you help me!

PS: I'm from Germany, so please excuse my bad english!:D


RE: Redirect Player - NiLSPACE - 10-30-2015

Hello and welcome to the forum Smile

You'll probably want to send a player with BungeeCord to another server. Zee1234 is working on that: https://forum.cuberite.org/showthread.php?tid=2168

You can't "get" a different player due to multithreading issues. Instead we use callbacks:
function OnPlayerRightClick(a_Player, All other parameters)
   local TargetOtherPlayer = "TargetPlayer"
   cRoot:Get():FindAndDoWithPlayer(TargetOtherPlayer, function(a_Player)
         -- Do stuff with the other player.
      end
   )
end



RE: Redirect Player - Zee1234 - 11-02-2015

https://forum.cuberite.org/showthread.php?tid=2179 < That's a pretty simple BungeeButtons plugin. It uses buttons, not signs, but otherwise works the same as yours sounds like it does.

If you want to create the bungeecord plugin messages yourself, it's something like this:

len = string.len(servername)
cPlayer:GetClientHandle():SendPluginMessage("BungeeCord","\0\7Connect" .. string.char(math.floor(len/256),len % 256) .. servername)


I've also written a plugin messaging library, if you want to use it. Here's the source (no separate GitHub yet, and where I do have it hosted, it requires my personal function library.)
[spoiler]
=======================================Defining the container table
--All functions in this library are elements of the table PMLib so as to not polute the namespace while providing users access to every function.
--"new" initializes the creation of a plugin message
--"write" functions handle making the "string" that gets send as the message.
--"read" functions handle manipulating the string recieved from a plugin message and getting you the information you want.
--This is never nessecary (if you send as long, any value will work), but it is nice.
--PMLib.FindLen is an INCREDIBLY useful function. It finds the length of the next section of the message. Do note that every read function does this already (or knows the length ahead of time), so FindLen is mostly for your own use if you choose to parse manually.

local PMLib = {}

function PMLib.FindLen(a_str)
  return string.byte(a_str,1) * 256 + string.byte(a_str,2), a_str:sub(3)
end

--=======================================Begin the creation of a Plugin Message
--Plugin messages are send like this:
--cPlayer:GetClientHandle():SendPluginMessage(channel,message)
--PMLib:new(channel) creates a tablethat allows for chainable message construction. This means that, instead of
--..SendPluginMessage("BungeeCord",PMLib.writeUTF("Hi!") .. PMLib.writeInt(270))
--We can do
--..SendPluginMessage(PMLib:new("BungeeCord"):writeUTF("Hi!"):writeInt(270):GetOut())
--In addition, at any time, you can pause your writing and read the table that gets outputted. Ex:
--local obj = PMLib:new("BungeeCord"):writeUTF("Hi!)
--local storedmessage = obj.Msg
function PMLib:new(a_Channel) -- Thanks to NilSpace for this
  local obj = {}
  setmetatable(obj, PMLib)
  self.__index = self
  
  obj.Channel = a_Channel
  obj.Msg = ""
   
  return obj
end

--=======================================Define the message
--These functions are chainable to each other and PMLib:new(channel)
--They can also be used on the table returned by PMLib:new(channel) and any other write function.
--Do note that these DO NOT work unless you use PMLib:new first to create the table that they manipulate.
function PMLib:writeUTF(a_str) --Thanks to NilSpace for this too
  assert(type(a_str) == "string", "Not a string!")
  local len = a_str:len()
  self.Msg = self.Msg .. string.char((len-127)/256,len % 256) .. a_str
  return self
end

function PMLib:writeByte(n) --Integer composed of 1 byte
  assert(not (n > 127),n .. " is too large")
  assert(not (n < -128),n .. " is too small")
  n = (n < 0) and (256 + n) or n
  self.Msg = self.Msg .. string.char(n%256)
  return self
end

function PMLib:writeShort(n) --Integer composed of 2 bytes
  assert(not (n > 32767),n .. " is too large")
  assert(not (n < -32768),n .. " is too small")
  n = (n < 0) and (65536 + n) or n
  self.Msg = self.Msg .. string.char((math.modf(n/256))%256,n%256)
  return self
end

function PMLib:writeInt(n) --Integer composed of 4 bytes
  assert(not (n > 2147483647),n .. " is too large")
  assert(not (n < -2147483648),n .. " is too small")
  -- adjust for 2's complement
  n = (n < 0) and (4294967296 + n) or n
  self.Msg = self.Msg .. string.char((math.modf(n/16777216))%256, (math.modf(n/65536))%256, (math.modf(n/256))%256, n%256)
  return self
end

function PMLib:writeLong(n) --Integer composed of 8 bytes
  assert(not (n > 9223372036854775807),n .. " is too large")
  assert(not (n < -9223372036854775808),n .. " is too small")
  n = (n < 0) and (1 + n) or n
  self.Msg = self.Msg .. string.char((math.modf(n/72057594037927936))%256,(math.modf(n/281474976710656))%256,(math.modf(n/1099511627776))%256,(math.modf(n/4294967296))%256,(math.modf(n/16777216))%256,(math.modf(n/65536))%256,(math.modf(n/256))%256,n%256)
  return self
end

function PMLib:writeBool(a_state) --True or False
  assert(type(a_state) == "boolean","Input is not a boolean!")
  if a_state then self.Msg = self.Msg .. string.char(0,1,1) else self.Msg = self.Msg .. string.char(0,1,0) end
  return self
end

--=======================================Return final values
--Once you have finished writing your message, throw
--:GetOut()
--onto the end of your chain, or your defined table.
--This function returns the channel (as defined in PMLib:new) and the message you created, meaning you can just plop it in a "SendPluginMessage" function and be done with it.
function PMLib:GetOut()
    return self.Channel, self.Msg
end

--=======================================Prepare to parse
--When you recieve a plugin message, the "message" section is an array of bytes that Cuberite represents as a string
--That string isn't super useful. PMLib:startparse prepares the string for manipulation by the "read" functions.
--PMLib:startparse(message) returns a table. The table can be to a variable and the variable manipulated by the "read" functions.
function PMLib:startparse(a_mess)
  local obj = {}
  setmetatable(obj, PMLib)
  self.__index = self
  
  obj.Msg = a_mess
  obj.arr = {}
  
  return obj
end

--=======================================Parse Message
--Each of these functions will read the byte string and output a specific type of value to a new element in an array.
--This array is stored in the parent object (a temporary object if you go from startparse to GetIn without defining an object
--or the object that you defined to be equal to startparse + and reads you did)
--Don't worry, you don't have to remember where you stored the array, you have have it extracted at the end.
--Be careful to use this in the exact order they have to be used. It is nearly impossible to do error checking with this
--As such, none has been implemented! The pressure is on you to make sure it's correct.
--If you just want to used BungeeCord plugin messages, I suggest you used the BPMLib that can also be found in this directory.
--It has automatic handling of most BungeeCord subchannels, both inbound and outbound, and utilizes this library, making it fully compatible!
function PMLib:readUTF()
  local len = tonumber(string.byte(self.Msg,1)) * 256 + tonumber(string.byte(self.Msg,2))
  self.arr[#self.arr + 1] = self.Msg:sub(3,len+2)
  self.Msg = self.Msg:sub(len+3)
  return self
end

function PMLib:readByte()
  local n = tonumber(self.Msg:byte(1))
  n = (n > 127) and (n - 256) or n
  self.arr[#self.arr + 1] = n
  self.Msg = self.Msg:sub(4)
  return self
end

function PMLib:readShort()
  local n = tonumber(self.Msg:byte(1))*256+tonumber(self.Msg:byte(2))
  n = (n > 32767) and (n - 65536) or n
  self.arr[#self.arr + 1] = n
  self.Msg = self.Msg:sub(5)
  return self
end

function PMLib:readInt()
  local n = tonumber(self.Msg:byte(1))*16777216 + tonumber(self.Msg:byte(2))*65536 + tonumber(self.Msg:byte(3))*256 + tonumber(self.Msg:byte(4))
  n = (n > 2147483647) and (n - 4294967296) or n
  self.arr[#self.arr + 1] = n
  self.Msg = self.Msg:sub(7)
  return self
end

function PMLib:readLong()
  local n = tonumber(self.Msg:byte(1))*72057594037927936 + tonumber(self.Msg:byte(2))*281474976710656 + tonumber(self.Msg:byte(3))*1099511627776 + tonumber(self.Msg:byte(4))*4294967296 + tonumber(self.Msg:byte(5))*16777216 + tonumber(self.Msg:byte(6))*65536 + tonumber(self.Msg:byte(9))*256 + tonumber(self.Msg:byte(10))
  n = (n > 9223372036854775807) and (n - 18446744073709551616) or n, self.Msg:sub(11)
  self.arr[#self.arr + 1] = n
  self.Msg = self.Msg:sub(11)
  return self
end

function PMLib:readBool()
  assert(self.Msg:byte() == 0 and self.Msg:byte(2) == 1,"Not a boolean value!")
  assert(self.Msg:byte(3) == 0 or self.Msg:byte(3) == 1,"Not a boolean value!")
  self.arr[#self.arr + 1] = self.Msg:byte(3) == 0 and false or true
  self.Msg = self.Msg:sub(4)
  return self
end

--=======================================Return final values
--Like I said above, you have have the array automatically extracted.
--Just slap a :GetIn() onto the end of your chain and it will return an array of the values you parsed!
function PMLib:GetIn()
    return self.arr
end
  


--=======================================Experimental functions
--While they work, I do not promise accuracy.
--They seem to be accurate to 2 decimal places, however I have not done extensive testing.
--An alternative is to use math.modf to separate out the fraction and the integer, multiple the fraction by 10 enough times to make it a decimal, then send the two numbers as two numbers, and undo at the other end.
--A better solution to this may come with a future change to the Cuberite API, or someone who's better at coding than I am.
--And yes, these use the ZLib (a library of functions I have for myself). If you'd rather not include ZLib and don't plan on using read/write float/double, I suggest you leave these functions commented.
--If you want them, however, simply add a dash in the line below and VOILA! Comment's gone.
--[[
function PMLib:writeFloat(a_num)  --32 bit IEEE 754-1985 floating point
  
end

function PMLib:readFloat()
  local bytestring = self.Msg:sub(1,4)
  self.Msg = self.Msg:sub(5)
  local num = ZLib.readFloat
  self.arr[#self.arr + 1] = num
  return self
end

function PMLib:writeDouble(a_num) --64 bit IEEE 754-1985 floating point
  self.Msg = self.Msg .. ZLib.double2ByteString(a_num)
end


function PMLib:readDouble()
  local bytestring = self.Msg:sub(1,8)
  self.Msg = self.Msg:sub(9)
  self.arr[#self.arr + 1] = ZLib.byteString2Double(bytestring)
  return self
end
--]]
--=======================================End of experimental functions

--=======================================No seriously. **** this with a wooden spoon. Floats were hard enough, this is torture.
--[[ Unused because **** this...
function PMLib:readUTF16()
  
end

function PMLib:writeUTF16(a_char)
  
end

--]]

return PMLib
[/spoiler]
Here's how you use it:
To start the creation of a plugin message, you do:
local ccli = cPlayer:GetClientHandle()
ccli:SendPluginMessage(PMLib:new(Channel. Put "BungeeCord" for a bungeecord message, MC|Animation for a MC Animation channel (weird..), etc):write{type of data}({data}):write{type of data}({data}) : ... :GetOut())

Types of data can be UTF (string), Byte (integer number between -2^7 and 2^7-1), Short (integer number between -2^15 and 2^15-1), Int (integer number between -2^31 and 2^31-1), Long (integer number between -2^63 and 2^63-1), and Bool (true or false boolean). So, to send a Connect message using a cPlayer class object from an On right click hook, you would do:
cPlayer:GetClientHandle():SendPluginMessage(PMLib:new("BungeeCord"):writeUTF("Connect"):writeUTF("server name"):GetOut())
And you're done!

Reading has the same data types, and can be done in essentially the same way. The On Plugin Message Hook returns a "string" as it's interpretation of the message. To read a message, use:
local messagearray = PMLib:startparse(message from hook call):readUTF():readInt():readByte():readBool(): ... :GetIn()

All of the read and write functions, as well as PMLib:new() and PMLib:startparse, return a PMLib-like object, so you can, for example, create part of a statement. Let's say you use a custom plugin channel to communicate with a client-side mod (like WorldEdit CUI). If you use it often, you could create a global variable called MyFrequentMessage and set it equal to PMLib:new(My channel):writeUTF(The string I always have here) and then later, when you need to send a PM, use MyFrequentMessage:writeInt(Thing that's dynamically written):writeBool(Other thing that is changed frequently):GetOut() and you now have a message to "My Channel" with all the proper values, while saving yourself a few CPU cycles.

Just be careful: while the write functions provide error checking, the read functions don't. They actually can't. So make sure you read in the right order.


RE: Redirect Player - Nether Mc - 11-03-2015

(10-30-2015, 09:19 PM)NiLSPACE Wrote: Hello and welcome to the forum Smile

You'll probably want to send a player with BungeeCord to another server. Zee1234 is working on that: https://forum.cuberite.org/showthread.php?tid=2168

You can't "get" a different player due to multithreading issues. Instead we use callbacks:
function OnPlayerRightClick(a_Player, All other parameters)
   local TargetOtherPlayer = "TargetPlayer"
   cRoot:Get():FindAndDoWithPlayer(TargetOtherPlayer, function(a_Player)
         -- Do stuff with the other player.
      end
   )
end

Ok, thanks !

(11-02-2015, 09:06 AM)Zee1234 Wrote: https://forum.cuberite.org/showthread.php?tid=2179 < That's a pretty simple BungeeButtons plugin. It uses buttons, not signs, but otherwise works the same as yours sounds like it does.

If you want to create the bungeecord plugin messages yourself, it's something like this:

len = string.len(servername)
cPlayer:GetClientHandle():SendPluginMessage("BungeeCord","\0\7Connect" .. string.char(math.floor(len/256),len % 256) .. servername)


I've also written a plugin messaging library, if you want to use it. Here's the source (no separate GitHub yet, and where I do have it hosted, it requires my personal function library.)
[spoiler]
=======================================Defining the container table
--All functions in this library are elements of the table PMLib so as to not polute the namespace while providing users access to every function.
--"new" initializes the creation of a plugin message
--"write" functions handle making the "string" that gets send as the message.
--"read" functions handle manipulating the string recieved from a plugin message and getting you the information you want.
--This is never nessecary (if you send as long, any value will work), but it is nice.
--PMLib.FindLen is an INCREDIBLY useful function. It finds the length of the next section of the message. Do note that every read function does this already (or knows the length ahead of time), so FindLen is mostly for your own use if you choose to parse manually.

local PMLib = {}

function PMLib.FindLen(a_str)
  return string.byte(a_str,1) * 256 + string.byte(a_str,2), a_str:sub(3)
end

--=======================================Begin the creation of a Plugin Message
--Plugin messages are send like this:
--cPlayer:GetClientHandle():SendPluginMessage(channel,message)
--PMLib:new(channel) creates a tablethat allows for chainable message construction. This means that, instead of
--..SendPluginMessage("BungeeCord",PMLib.writeUTF("Hi!") .. PMLib.writeInt(270))
--We can do
--..SendPluginMessage(PMLib:new("BungeeCord"):writeUTF("Hi!"):writeInt(270):GetOut())
--In addition, at any time, you can pause your writing and read the table that gets outputted. Ex:
--local obj = PMLib:new("BungeeCord"):writeUTF("Hi!)
--local storedmessage = obj.Msg
function PMLib:new(a_Channel) -- Thanks to NilSpace for this
  local obj = {}
  setmetatable(obj, PMLib)
  self.__index = self
  
  obj.Channel = a_Channel
  obj.Msg = ""
   
  return obj
end

--=======================================Define the message
--These functions are chainable to each other and PMLib:new(channel)
--They can also be used on the table returned by PMLib:new(channel) and any other write function.
--Do note that these DO NOT work unless you use PMLib:new first to create the table that they manipulate.
function PMLib:writeUTF(a_str) --Thanks to NilSpace for this too
  assert(type(a_str) == "string", "Not a string!")
  local len = a_str:len()
  self.Msg = self.Msg .. string.char((len-127)/256,len % 256) .. a_str
  return self
end

function PMLib:writeByte(n) --Integer composed of 1 byte
  assert(not (n > 127),n .. " is too large")
  assert(not (n < -128),n .. " is too small")
  n = (n < 0) and (256 + n) or n
  self.Msg = self.Msg .. string.char(n%256)
  return self
end

function PMLib:writeShort(n) --Integer composed of 2 bytes
  assert(not (n > 32767),n .. " is too large")
  assert(not (n < -32768),n .. " is too small")
  n = (n < 0) and (65536 + n) or n
  self.Msg = self.Msg .. string.char((math.modf(n/256))%256,n%256)
  return self
end

function PMLib:writeInt(n) --Integer composed of 4 bytes
  assert(not (n > 2147483647),n .. " is too large")
  assert(not (n < -2147483648),n .. " is too small")
  -- adjust for 2's complement
  n = (n < 0) and (4294967296 + n) or n
  self.Msg = self.Msg .. string.char((math.modf(n/16777216))%256, (math.modf(n/65536))%256, (math.modf(n/256))%256, n%256)
  return self
end

function PMLib:writeLong(n) --Integer composed of 8 bytes
  assert(not (n > 9223372036854775807),n .. " is too large")
  assert(not (n < -9223372036854775808),n .. " is too small")
  n = (n < 0) and (1 + n) or n
  self.Msg = self.Msg .. string.char((math.modf(n/72057594037927936))%256,(math.modf(n/281474976710656))%256,(math.modf(n/1099511627776))%256,(math.modf(n/4294967296))%256,(math.modf(n/16777216))%256,(math.modf(n/65536))%256,(math.modf(n/256))%256,n%256)
  return self
end

function PMLib:writeBool(a_state) --True or False
  assert(type(a_state) == "boolean","Input is not a boolean!")
  if a_state then self.Msg = self.Msg .. string.char(0,1,1) else self.Msg = self.Msg .. string.char(0,1,0) end
  return self
end

--=======================================Return final values
--Once you have finished writing your message, throw
--:GetOut()
--onto the end of your chain, or your defined table.
--This function returns the channel (as defined in PMLib:new) and the message you created, meaning you can just plop it in a "SendPluginMessage" function and be done with it.
function PMLib:GetOut()
    return self.Channel, self.Msg
end

--=======================================Prepare to parse
--When you recieve a plugin message, the "message" section is an array of bytes that Cuberite represents as a string
--That string isn't super useful. PMLib:startparse prepares the string for manipulation by the "read" functions.
--PMLib:startparse(message) returns a table. The table can be to a variable and the variable manipulated by the "read" functions.
function PMLib:startparse(a_mess)
  local obj = {}
  setmetatable(obj, PMLib)
  self.__index = self
  
  obj.Msg = a_mess
  obj.arr = {}
  
  return obj
end

--=======================================Parse Message
--Each of these functions will read the byte string and output a specific type of value to a new element in an array.
--This array is stored in the parent object (a temporary object if you go from startparse to GetIn without defining an object
--or the object that you defined to be equal to startparse + and reads you did)
--Don't worry, you don't have to remember where you stored the array, you have have it extracted at the end.
--Be careful to use this in the exact order they have to be used. It is nearly impossible to do error checking with this
--As such, none has been implemented! The pressure is on you to make sure it's correct.
--If you just want to used BungeeCord plugin messages, I suggest you used the BPMLib that can also be found in this directory.
--It has automatic handling of most BungeeCord subchannels, both inbound and outbound, and utilizes this library, making it fully compatible!
function PMLib:readUTF()
  local len = tonumber(string.byte(self.Msg,1)) * 256 + tonumber(string.byte(self.Msg,2))
  self.arr[#self.arr + 1] = self.Msg:sub(3,len+2)
  self.Msg = self.Msg:sub(len+3)
  return self
end

function PMLib:readByte()
  local n = tonumber(self.Msg:byte(1))
  n = (n > 127) and (n - 256) or n
  self.arr[#self.arr + 1] = n
  self.Msg = self.Msg:sub(4)
  return self
end

function PMLib:readShort()
  local n = tonumber(self.Msg:byte(1))*256+tonumber(self.Msg:byte(2))
  n = (n > 32767) and (n - 65536) or n
  self.arr[#self.arr + 1] = n
  self.Msg = self.Msg:sub(5)
  return self
end

function PMLib:readInt()
  local n = tonumber(self.Msg:byte(1))*16777216 + tonumber(self.Msg:byte(2))*65536 + tonumber(self.Msg:byte(3))*256 + tonumber(self.Msg:byte(4))
  n = (n > 2147483647) and (n - 4294967296) or n
  self.arr[#self.arr + 1] = n
  self.Msg = self.Msg:sub(7)
  return self
end

function PMLib:readLong()
  local n = tonumber(self.Msg:byte(1))*72057594037927936 + tonumber(self.Msg:byte(2))*281474976710656 + tonumber(self.Msg:byte(3))*1099511627776 + tonumber(self.Msg:byte(4))*4294967296 + tonumber(self.Msg:byte(5))*16777216 + tonumber(self.Msg:byte(6))*65536 + tonumber(self.Msg:byte(9))*256 + tonumber(self.Msg:byte(10))
  n = (n > 9223372036854775807) and (n - 18446744073709551616) or n, self.Msg:sub(11)
  self.arr[#self.arr + 1] = n
  self.Msg = self.Msg:sub(11)
  return self
end

function PMLib:readBool()
  assert(self.Msg:byte() == 0 and self.Msg:byte(2) == 1,"Not a boolean value!")
  assert(self.Msg:byte(3) == 0 or self.Msg:byte(3) == 1,"Not a boolean value!")
  self.arr[#self.arr + 1] = self.Msg:byte(3) == 0 and false or true
  self.Msg = self.Msg:sub(4)
  return self
end

--=======================================Return final values
--Like I said above, you have have the array automatically extracted.
--Just slap a :GetIn() onto the end of your chain and it will return an array of the values you parsed!
function PMLib:GetIn()
    return self.arr
end
  


--=======================================Experimental functions
--While they work, I do not promise accuracy.
--They seem to be accurate to 2 decimal places, however I have not done extensive testing.
--An alternative is to use math.modf to separate out the fraction and the integer, multiple the fraction by 10 enough times to make it a decimal, then send the two numbers as two numbers, and undo at the other end.
--A better solution to this may come with a future change to the Cuberite API, or someone who's better at coding than I am.
--And yes, these use the ZLib (a library of functions I have for myself). If you'd rather not include ZLib and don't plan on using read/write float/double, I suggest you leave these functions commented.
--If you want them, however, simply add a dash in the line below and VOILA! Comment's gone.
--[[
function PMLib:writeFloat(a_num)  --32 bit IEEE 754-1985 floating point
  
end

function PMLib:readFloat()
  local bytestring = self.Msg:sub(1,4)
  self.Msg = self.Msg:sub(5)
  local num = ZLib.readFloat
  self.arr[#self.arr + 1] = num
  return self
end

function PMLib:writeDouble(a_num) --64 bit IEEE 754-1985 floating point
  self.Msg = self.Msg .. ZLib.double2ByteString(a_num)
end


function PMLib:readDouble()
  local bytestring = self.Msg:sub(1,8)
  self.Msg = self.Msg:sub(9)
  self.arr[#self.arr + 1] = ZLib.byteString2Double(bytestring)
  return self
end
--]]
--=======================================End of experimental functions

--=======================================No seriously. **** this with a wooden spoon. Floats were hard enough, this is torture.
--[[ Unused because **** this...
function PMLib:readUTF16()
  
end

function PMLib:writeUTF16(a_char)
  
end

--]]

return PMLib
[/spoiler]
Here's how you use it:
To start the creation of a plugin message, you do:
local ccli = cPlayer:GetClientHandle()
ccli:SendPluginMessage(PMLib:new(Channel. Put "BungeeCord" for a bungeecord message, MC|Animation for a MC Animation channel (weird..), etc):write{type of data}({data}):write{type of data}({data}) : ... :GetOut())

Types of data can be UTF (string), Byte (integer number between -2^7 and 2^7-1), Short (integer number between -2^15 and 2^15-1), Int (integer number between -2^31 and 2^31-1), Long (integer number between -2^63 and 2^63-1), and Bool (true or false boolean). So, to send a Connect message using a cPlayer class object from an On right click hook, you would do:
cPlayer:GetClientHandle():SendPluginMessage(PMLib:new("BungeeCord"):writeUTF("Connect"):writeUTF("server name"):GetOut())
And you're done!

Reading has the same data types, and can be done in essentially the same way. The On Plugin Message Hook returns a "string" as it's interpretation of the message. To read a message, use:
local messagearray = PMLib:startparse(message from hook call):readUTF():readInt():readByte():readBool(): ... :GetIn()

All of the read and write functions, as well as PMLib:new() and PMLib:startparse, return a PMLib-like object, so you can, for example, create part of a statement. Let's say you use a custom plugin channel to communicate with a client-side mod (like WorldEdit CUI). If you use it often, you could create a global variable called MyFrequentMessage and set it equal to PMLib:new(My channel):writeUTF(The string I always have here) and then later, when you need to send a PM, use MyFrequentMessage:writeInt(Thing that's dynamically written):writeBool(Other thing that is changed frequently):GetOut() and you now have a message to "My Channel" with all the proper values, while saving yourself a few CPU cycles.

Just be careful: while the write functions provide error checking, the read functions don't. They actually can't. So make sure you read in the right order.

Ok, thanks! Can I use your code in my plugin? Do I have to setup 2 Servers to use Bungee Cord? I don't exactly know how that works, cause a friend helped me with forwarding, dnydns etc. .


RE: Redirect Player - xoft - 11-04-2015

I feel a clarification is needed. You CANNOT redirect a player to another server that you do not own. There's simply no means in the protocol to do that. It's only possible to move a player from one server to another IF both of those servers are part of the same network and they are using BungeeCord as the gateway. In this setup, instead of connecting to the server directly, players connect to the BungeeCord gateway and it takes care of the moves transparently.


RE: Redirect Player - Zee1234 - 11-04-2015

(11-03-2015, 08:38 PM)Nether Mc Wrote: Ok, thanks! Can I use your code in my plugin? Do I have to setup 2 Servers to use Bungee Cord? I don't exactly know how that works, cause a friend helped me with forwarding, dnydns etc. .

You are more than welcome to use my code. It's licensed under the MIT license (just forgot to include that bit in the sample above, but the license exists in my GitHub of BungeeButtons). Now read below:

(11-04-2015, 12:02 AM)xoft Wrote: I feel a clarification is needed. You CANNOT redirect a player to another server that you do not own. There's simply no means in the protocol to do that. It's only possible to move a player from one server to another IF both of those servers are part of the same network and they are using BungeeCord as the gateway. In this setup, instead of connecting to the server directly, players connect to the BungeeCord gateway and it takes care of the moves transparently.

This is correct. You would need to learn how to set this up or get your friend to set it up for you. If this isn't an option, you are better off using a multi-world setup, which my code will not be able to help you with.

Good luck!