mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 21:53:46 +03:00
Upload
This commit is contained in:
198
gamemodes/ixhl2rp/plugins/phone/libs/sv_connections.lua
Normal file
198
gamemodes/ixhl2rp/plugins/phone/libs/sv_connections.lua
Normal file
@@ -0,0 +1,198 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
ix.phone = ix.phone or {}
|
||||
ix.phone.switch = ix.phone.switch or {}
|
||||
|
||||
-- a volatile table for caching ongoing connections
|
||||
ix.phone.switch.connections = ix.phone.switch.connections or {}
|
||||
|
||||
function ix.phone.switch:ConnectionValid(connID)
|
||||
if (self.connections[connID] == false) then
|
||||
return false
|
||||
end
|
||||
|
||||
return istable(self.connections[connID])
|
||||
end
|
||||
|
||||
function ix.phone.switch:buildNewConnectionNode(connID, extID, extNum)
|
||||
-- helper function to create source requests for connections
|
||||
-- constructs a table that can be used by ix.phone.switch:connect()
|
||||
if (!self:ConnectionValid(connID)) then
|
||||
return
|
||||
end
|
||||
|
||||
if (!self.connections[connID].nodes) then
|
||||
self.connections[connID].nodes = {}
|
||||
end
|
||||
|
||||
local nodeID = #self.connections[connID].nodes + 1
|
||||
self.connections[connID].nodes[nodeID] = {}
|
||||
self.connections[connID].nodes[nodeID]["exchange"] = extID
|
||||
self.connections[connID].nodes[nodeID]["extension"] = extNum
|
||||
end
|
||||
|
||||
function ix.phone.switch:buildNewConnection()
|
||||
-- helper function to that creates a new connection
|
||||
|
||||
-- attempt to reuse a freshly terminated connection
|
||||
for id, conn in ipairs(self.connections) do
|
||||
if (conn == false) then
|
||||
self.connections[id] = {}
|
||||
return id
|
||||
end
|
||||
end
|
||||
|
||||
-- no terminated connections
|
||||
connectionID = #self.connections + 1
|
||||
self.connections[connectionID] = {}
|
||||
|
||||
return connectionID
|
||||
end
|
||||
|
||||
function ix.phone.switch:Disconnect(connID, noNotify)
|
||||
-- disconnects provided connection at connID
|
||||
-- if notify is set, then it wont notify listeners that the connection is terminated
|
||||
if (!istable(self.connections[connID])) then
|
||||
return
|
||||
end
|
||||
|
||||
local _nodes = self.connections[connID].nodes
|
||||
for _, node in ipairs(_nodes) do
|
||||
local recievers = self:getReceivers(node.exchange, node.extension)
|
||||
|
||||
if (!istable(recievers) or table.Count(recievers) < 1) then
|
||||
continue
|
||||
end
|
||||
|
||||
for _, reciever in ipairs(recievers) do
|
||||
local ent = self.endpoints:GetEndpoint(reciever.endID)
|
||||
if (ent and ent.HangUp and ent.isRinging) then
|
||||
ent:HangUp()
|
||||
end
|
||||
end
|
||||
|
||||
local listeners = self:getListenersFromRecvs(recievers)
|
||||
|
||||
if (!listeners or table.Count(listeners) < 1) then
|
||||
continue
|
||||
end
|
||||
|
||||
for _, listener in ipairs(listeners) do
|
||||
self:DisconnectClient(listener)
|
||||
end
|
||||
end
|
||||
|
||||
self.connections[connID] = false
|
||||
end
|
||||
|
||||
-- disconnects the client's status and notifies them of said status change
|
||||
-- IMPORTANT: Make sure you destroy the connection too!
|
||||
function ix.phone.switch:DisconnectClient(client)
|
||||
if (!client or !IsValid(client)) then
|
||||
return ErrorNoHaltWithStack("Attempt to disconnect invalid client "..tostring(client))
|
||||
end
|
||||
|
||||
local character = client:GetCharacter()
|
||||
if (!istable(character)) then
|
||||
return ErrorNoHaltWithStack("Attempt to disconnect client with invalid character "..tostring(character))
|
||||
end
|
||||
|
||||
self:ResetCharVars(character)
|
||||
self:NotifyStatusChange(client, false, false)
|
||||
end
|
||||
|
||||
function ix.phone.switch:NotifyStatusChange(client, bCallActive, bInCall)
|
||||
net.Start("ixConnectedCallStatusChange")
|
||||
net.WriteBool(bCallActive)
|
||||
net.WriteBool(bInCall)
|
||||
net.Send(client)
|
||||
end
|
||||
|
||||
function ix.phone.switch:NotifyAllListenersOfStatusChange(endID, bCallActive, bInCall)
|
||||
local listeners = self.endpoints:GetListeners(endID)
|
||||
if (!listeners or table.Count(listeners) < 1) then
|
||||
return -- no need to do anything; no listeners
|
||||
end
|
||||
|
||||
for _, listener in ipairs(listeners) do
|
||||
-- notify all listeners of their call status change
|
||||
self:NotifyStatusChange(listener, bCallActive, bInCall)
|
||||
end
|
||||
end
|
||||
|
||||
function ix.phone.switch:getListenersFromRecvs(recievers)
|
||||
local listeners = {}
|
||||
for k, recv in ipairs(recievers) do
|
||||
-- there will almost always be one reciever.. but treating this as a list in case we ever do 'conference calls'
|
||||
local _listeners = self.endpoints:GetListeners(recv.endID)
|
||||
if (istable(_listeners)) then
|
||||
for _, listener in ipairs(_listeners) do
|
||||
listeners[table.Count(listeners) + 1] = listener
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return listeners
|
||||
end
|
||||
|
||||
function ix.phone.switch:getReceivers(extID, extNum)
|
||||
local conn = self:GetActiveConnection(extID, extNum)
|
||||
if (!istable(conn)) then
|
||||
return
|
||||
end
|
||||
|
||||
return self:getSourceRecieversFromConnection(conn.targetConnID,
|
||||
conn.sourceNodeID)
|
||||
end
|
||||
|
||||
function ix.phone.switch:GetListeners(extID, extNum)
|
||||
return self:getListenersFromRecvs(self:getReceivers(extID, extNum))
|
||||
end
|
||||
|
||||
function ix.phone.switch:GetReceivers(extID, extNum)
|
||||
local conn = self:GetActiveConnection(extID, extNum)
|
||||
if (!istable(conn)) then
|
||||
return
|
||||
end
|
||||
|
||||
return self:getSourceRecieversFromConnection(conn.targetConnID,
|
||||
conn.sourceNodeID)
|
||||
end
|
||||
|
||||
-- returns the active connection in the form of {"targetConnID", "sourceNodeID"} if one is present
|
||||
function ix.phone.switch:GetActiveConnection(extID, extNum)
|
||||
for connID, conn in ipairs(self.connections) do
|
||||
if (conn == false) then
|
||||
continue
|
||||
end
|
||||
|
||||
for nodeID, node in ipairs(conn.nodes) do
|
||||
if (node["exchange"] == extID and node["extension"] == extNum) then
|
||||
-- source is present in this connection
|
||||
return {targetConnID = connID, sourceNodeID = nodeID}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- returns the actively connected (except for the source) recievers for a given connection
|
||||
function ix.phone.switch:getSourceRecieversFromConnection(connID, sourceNodeID)
|
||||
local res = {}
|
||||
for nodeID, node in ipairs(self.connections[connID].nodes) do
|
||||
if (nodeID != sourceNodeID) then
|
||||
-- we want to return this as it exists in the exchange as that will give us
|
||||
-- extra details the node tree does not contain such as name and endID
|
||||
res[#res + 1] = self:GetDest(node["exchange"], node["extension"])
|
||||
end
|
||||
end
|
||||
|
||||
return res
|
||||
end
|
||||
123
gamemodes/ixhl2rp/plugins/phone/libs/sv_endpoints.lua
Normal file
123
gamemodes/ixhl2rp/plugins/phone/libs/sv_endpoints.lua
Normal file
@@ -0,0 +1,123 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
ix.phone = ix.phone or {}
|
||||
ix.phone.switch = ix.phone.switch or {}
|
||||
|
||||
-- a flat list of all the entities. each entity has an associated 'listeners' table which contains all of the players actively connected to that entity
|
||||
ix.phone.switch.endpoints = ix.phone.switch.endpoints or {}
|
||||
|
||||
function ix.phone.switch.endpoints:exists(id)
|
||||
return self[id] != nil
|
||||
end
|
||||
|
||||
function ix.phone.switch.endpoints:entExists(entIdx)
|
||||
for id, ent in ipairs(self) do
|
||||
if (entIdx == ent:EntIndex()) then
|
||||
return id
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function ix.phone.switch.endpoints:Register(ent)
|
||||
-- assigns an ID. if the ent already exists then it will return the existing id
|
||||
-- we need to have our own ID here rather than the index because the entity index might change but
|
||||
-- in that case the id shouldn't
|
||||
|
||||
local entExists = self:entExists(ent:EntIndex())
|
||||
if (entExists != nil) then
|
||||
return nil
|
||||
end
|
||||
|
||||
local newID = math.random(1000, 9999)
|
||||
if (self:exists(newID)) then
|
||||
return nil
|
||||
end
|
||||
|
||||
self[newID] = ent
|
||||
return newID
|
||||
end
|
||||
|
||||
function ix.phone.switch.endpoints:DeRegister(id)
|
||||
self[id] = nil
|
||||
end
|
||||
|
||||
function ix.phone.switch.endpoints:GetEndpoint(id)
|
||||
-- returns the associated entity table
|
||||
if (self:exists(id)) then
|
||||
return self[id]
|
||||
end
|
||||
end
|
||||
|
||||
function ix.phone.switch.endpoints:AddListener(id, client)
|
||||
if (!istable(self[id].listeners)) then
|
||||
self[id].listeners = {}
|
||||
end
|
||||
|
||||
for _, listener in ipairs(self[id].listeners) do
|
||||
if (listener == client) then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
self[id].listeners[table.Count(self[id].listeners) + 1] = client
|
||||
end
|
||||
|
||||
function ix.phone.switch.endpoints:RmListener(id, client)
|
||||
if (!istable(self[id].listeners)) then
|
||||
return
|
||||
end
|
||||
|
||||
for k, listener in ipairs(self[id].listeners) do
|
||||
if (listener == client) then
|
||||
self[id].listeners[k] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ix.phone.switch.endpoints:GetListeners(id)
|
||||
return self[id].listeners
|
||||
end
|
||||
|
||||
function ix.phone.switch.endpoints:RingEndpoint(id, callback)
|
||||
-- rings and endpoint and, if the phone is picked up, it will call callback as true. otherwise false
|
||||
-- if the destination is unavailable or busy then it will return nil
|
||||
local ent = self:GetEndpoint(id)
|
||||
|
||||
if (ent.inUse or ent.isRinging) then
|
||||
return nil
|
||||
end
|
||||
|
||||
ent:EnterRing(callback)
|
||||
end
|
||||
|
||||
function ix.phone.switch.endpoints:GetPlayersInRadiusFromPos(pos, radius)
|
||||
local entsInside = ents.FindInSphere(pos, radius)
|
||||
local res = {}
|
||||
|
||||
for _, _ent in ipairs(entsInside) do
|
||||
if (_ent:IsPlayer() and _ent.GetCharacter and _ent:GetCharacter()) then
|
||||
res[_ent:SteamID64()] = _ent
|
||||
end
|
||||
end
|
||||
|
||||
return res
|
||||
end
|
||||
|
||||
-- returns a list of players within X radius of the endpoint
|
||||
function ix.phone.switch.endpoints:GetPlayersInRadius(id, radius)
|
||||
local ent = self:GetEndpoint(id)
|
||||
if (!ent) then
|
||||
return
|
||||
end
|
||||
|
||||
return self:GetPlayersInRadiusFromPos(ent:GetPos(), radius)
|
||||
end
|
||||
100
gamemodes/ixhl2rp/plugins/phone/libs/sv_exchange.lua
Normal file
100
gamemodes/ixhl2rp/plugins/phone/libs/sv_exchange.lua
Normal file
@@ -0,0 +1,100 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
ix.phone = ix.phone or {}
|
||||
ix.phone.switch = ix.phone.switch or {}
|
||||
|
||||
-- a table used for managing pbxs and their members
|
||||
ix.phone.switch.exchanges = ix.phone.switch.exchanges or {}
|
||||
|
||||
--[[ The following is some boiler plate code for creating and managing extensions and exchanges
|
||||
In practice these things are just keys in a table and in the DB but it is probably best
|
||||
if you use the functions here and not directly modify ix.phone.switch.exchanges directly!
|
||||
|
||||
This is necessary to keep the switching code readable
|
||||
]]
|
||||
function ix.phone.switch:AddExchange(exID)
|
||||
if (self:ExchangeExists(exID)) then
|
||||
return false
|
||||
end
|
||||
|
||||
self.exchanges[exID] = {}
|
||||
return true
|
||||
end
|
||||
|
||||
function ix.phone.switch:RmExchange(exID)
|
||||
if (!self:ExchangeExists(exID)) then
|
||||
return false
|
||||
end
|
||||
|
||||
self.exchanges[exID] = nil
|
||||
return true
|
||||
end
|
||||
|
||||
function ix.phone.switch:ExchangeExists(exID)
|
||||
return self.exchanges[exID] != nil
|
||||
end
|
||||
|
||||
function ix.phone.switch:DestExists(exID, extNum)
|
||||
if (self.exchanges[exID] != nil) then
|
||||
return self.exchanges[exID][extNum] != nil
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function ix.phone.switch:AddDest(exID, extNum, extName, endID)
|
||||
-- returns false if destination exists or exchange doesn't
|
||||
-- set noDB if you do not wish to store this destination to the database
|
||||
if (self:DestExists(exID, extNum)) then
|
||||
return false
|
||||
end
|
||||
|
||||
self.exchanges[exID][extNum] = {}
|
||||
self.exchanges[exID][extNum]["name"] = extName or ""
|
||||
self.exchanges[exID][extNum]["endID"] = endID
|
||||
return true
|
||||
end
|
||||
|
||||
function ix.phone.switch:GetDest(exID, extNum)
|
||||
if (!self:DestExists(exID, extNum)) then
|
||||
return false
|
||||
end
|
||||
|
||||
return self.exchanges[exID][extNum]
|
||||
end
|
||||
|
||||
function ix.phone.switch:RmDest(exID, extNum)
|
||||
-- returns false if destination does not exist
|
||||
if (!self:DestExists(exID, extNum)) then
|
||||
return false
|
||||
end
|
||||
|
||||
self.exchanges[exID][extNum] = nil
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function ix.phone.switch:MvDest(fromExID, fromExtNum, toExID, toExtNum)
|
||||
if (!self:RmDest(fromExID, fromExtNum)) then
|
||||
return false
|
||||
end
|
||||
|
||||
return self:AddDest(toExID, toExtNum)
|
||||
end
|
||||
|
||||
function ix.phone.switch:SetName(exID, extNum, name)
|
||||
if (!self:DestExists(exID, extNum)) then
|
||||
return false
|
||||
end
|
||||
|
||||
self.endpoints[self.exchanges[exID][extNum]["endID"]].currentName = name
|
||||
return true
|
||||
end
|
||||
402
gamemodes/ixhl2rp/plugins/phone/libs/sv_switch.lua
Normal file
402
gamemodes/ixhl2rp/plugins/phone/libs/sv_switch.lua
Normal file
@@ -0,0 +1,402 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
-- this is a loose implementation of a virtual private business exchange (vPBX)
|
||||
ix.phone = ix.phone or {}
|
||||
ix.phone.switch = ix.phone.switch or {}
|
||||
ix.phone.switch.lineTestPBX = 9
|
||||
ix.phone.switch.lineTestExt = 999 -- reserved for testing
|
||||
|
||||
do
|
||||
-- set up ent to use for 2 way call testing
|
||||
timer.Simple(10, function()
|
||||
local lineTestEnt = ents.Create("landline_phone")
|
||||
lineTestEnt:SetPos(Vector(0, 0, 0))
|
||||
lineTestEnt:Spawn()
|
||||
lineTestEnt:SetNoDraw(true)
|
||||
-- if we dont do this then our landline point ent will fall through the world
|
||||
-- and get deleted
|
||||
local _phys = lineTestEnt:GetPhysicsObject()
|
||||
_phys:EnableGravity(false)
|
||||
_phys:EnableMotion(false)
|
||||
_phys:Sleep()
|
||||
|
||||
lineTestEnt.currentName = "Line Test"
|
||||
lineTestEnt.currentPBX = ix.phone.switch.lineTestPBX
|
||||
lineTestEnt.currentExtension = ix.phone.switch.lineTestExt
|
||||
|
||||
-- yes we need a real entity for this. doesn't have to be a landline but might as well
|
||||
ix.phone.switch.lineTestEnt = lineTestEnt
|
||||
end)
|
||||
end
|
||||
|
||||
-- (optional)
|
||||
-- takes in a dial sequence in the format of (exchange)(extension)
|
||||
-- ex: 1 234
|
||||
-- it returns it into a table as {"exchange", "extension"}
|
||||
function ix.phone.switch:decodeSeq(dialSeq)
|
||||
-- dial sequences must be strings, but must be a real number as well and must be 4 digits
|
||||
if (type(dialSeq) != "string" or tonumber(dialSeq) == nil) then
|
||||
return nil
|
||||
elseif (string.len(dialSeq) > 4 or string.len(dialSeq) < 3) then
|
||||
return nil
|
||||
end
|
||||
|
||||
local exchange = nil
|
||||
if (string.len(dialSeq) != 3) then -- otherwise it is a local dial (to endpoint in own exchange)
|
||||
exchange = tonumber(string.sub(dialSeq, 0, 1))
|
||||
if (exchange == nil or exchange < 1) then
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
-- the remaining digits should be the extension
|
||||
local ext = tonumber(string.sub(dialSeq, 2, 4))
|
||||
if (ext == nil or ext < 1) then
|
||||
return nil
|
||||
end
|
||||
|
||||
return {["exchange"] = exchange, ["extension"] = ext}
|
||||
end
|
||||
|
||||
function ix.phone.switch:BuildNewTwoWayConnection(sourceExc, sourceExt, destExc, destExt)
|
||||
local connID = self:buildNewConnection()
|
||||
self:buildNewConnectionNode(connID, sourceExc, sourceExt)
|
||||
self:buildNewConnectionNode(connID, destExc, destExt)
|
||||
|
||||
return connID
|
||||
end
|
||||
|
||||
function ix.phone.switch:Dial(sourceExc, sourceExt, dialSeq)
|
||||
if (!self:DestExists(sourceExc, sourceExt)) then
|
||||
return self.DialStatus.SourceNotExist
|
||||
end
|
||||
|
||||
--[[
|
||||
Decode the user provided dial sequence into a switchable pair of of pbx and ext
|
||||
]]
|
||||
if (!istable(dialSeq) and #dialSeq < 1) then
|
||||
return self.DialStatus.NoDialSeq
|
||||
end
|
||||
|
||||
local decodedDest = self:decodeSeq(dialSeq)
|
||||
|
||||
if (!istable(decodedDest)) then
|
||||
return self.DialStatus.CannotDecodeDial
|
||||
end
|
||||
|
||||
if (decodedDest.exchange == self.lineTestPBX and decodedDest.extension == self.lineTestExt) then
|
||||
self:StartLineTest(sourceExc, sourceExt)
|
||||
return self.DialStatus.DebugMode
|
||||
end
|
||||
|
||||
if (decodedDest.exchange == nil) then
|
||||
decodedDest.exchange = sourceExc
|
||||
end
|
||||
|
||||
if (!self:DestExists(decodedDest.exchange, decodedDest.extension)) then
|
||||
return self.DialStatus.NumberNotFound
|
||||
end
|
||||
|
||||
--[[
|
||||
Get the endpoint IDs and corresponding entities for source & destination
|
||||
]]
|
||||
local destination = self:GetDest(decodedDest.exchange, decodedDest.extension)
|
||||
local source = self:GetDest(sourceExc, sourceExt)
|
||||
|
||||
if (!destination.endID or !source.endID) then
|
||||
return self.DialStatus.EndpointNotFound
|
||||
end
|
||||
|
||||
local destEnt = self.endpoints:GetEndpoint(tonumber(destination.endID))
|
||||
local sourceEnt = self.endpoints:GetEndpoint(tonumber(source.endID))
|
||||
|
||||
--[[
|
||||
Check if the line is busy
|
||||
]]
|
||||
local _conn = self:GetActiveConnection(decodedDest.exchange, decodedDest.extension)
|
||||
if (_conn and istable(_conn) or destEnt.offHook) then
|
||||
return self.DialStatus.LineBusy
|
||||
end
|
||||
|
||||
--[[
|
||||
Build new connection for source & dest with the pbxs and exts.
|
||||
]]
|
||||
local connID = self:BuildNewTwoWayConnection(sourceExc, sourceExt,
|
||||
decodedDest.exchange, decodedDest.extension)
|
||||
|
||||
--[[
|
||||
Setup the callbacks and start the call
|
||||
]]
|
||||
local ringCallback = function(status)
|
||||
if (!status) then -- call did not go through so we need to clean up
|
||||
self:Disconnect(connID)
|
||||
end
|
||||
|
||||
self:NotifyAllListenersOfStatusChange(tonumber(destination.endID), status, status)
|
||||
self:NotifyAllListenersOfStatusChange(tonumber(source.endID), status, status)
|
||||
end
|
||||
|
||||
destEnt:EnterRing(ringCallback) -- set the target as ringing
|
||||
|
||||
local hangUpCallback = function(status)
|
||||
-- cleanup
|
||||
self:Disconnect(connID)
|
||||
end
|
||||
|
||||
destEnt.hangUpCallback = hangUpCallback
|
||||
sourceEnt.hangUpCallback = hangUpCallback
|
||||
|
||||
return self.DialStatus.Success
|
||||
end
|
||||
|
||||
-- returns back a list of player entities that are listening to the phone this character is speaking into
|
||||
function ix.phone.switch:GetCharacterActiveListeners(character)
|
||||
if (!istable(character)) then
|
||||
return
|
||||
end
|
||||
|
||||
local connMD = character:GetLandlineConnection()
|
||||
if (!connMD) then
|
||||
return
|
||||
end
|
||||
|
||||
return self:GetListeners(connMD.exchange, connMD.extension)
|
||||
end
|
||||
|
||||
function ix.phone.switch:GetPlayerActiveListeners(client)
|
||||
local character = client:GetCharacter()
|
||||
if (!istable(character)) then
|
||||
return nil
|
||||
end
|
||||
|
||||
return self:GetCharacterActiveListeners(character)
|
||||
end
|
||||
|
||||
-- rudely hangs up every single active call related to this character
|
||||
-- typically used when the player disconnects or switches chars mid call
|
||||
function ix.phone.switch:DisconnectActiveCallIfPresentOnClient(client)
|
||||
local character = client:GetCharacter()
|
||||
if (!istable(character)) then
|
||||
return
|
||||
end
|
||||
|
||||
local connMD = character:GetLandlineConnection()
|
||||
if (!istable(connMD) and !connMD["active"]) then
|
||||
-- probably ran hangup on a phone someone else was speaking on
|
||||
-- we should allow this in the future (maybe?) but for now we exit
|
||||
client:NotifyLocalized("You are not speaking on the phone.")
|
||||
return
|
||||
end
|
||||
|
||||
-- terminate any existing connections here
|
||||
local conn = self:GetActiveConnection(connMD["exchange"], connMD["extension"])
|
||||
if (!istable(conn)) then
|
||||
client:NotifyLocalized("Error: AttemptedHangupOnActivePhoneNoConn")
|
||||
-- This shouldn't be possible but if it happens then there is some lingering issue with
|
||||
-- this character's var being active when they are not in an active connection
|
||||
self:ResetCharVars(character)
|
||||
return
|
||||
end
|
||||
|
||||
self:Disconnect(conn["targetConnID"])
|
||||
end
|
||||
|
||||
-- returns whether or not the 'listener' is in an active phone call with 'speaker'
|
||||
function ix.phone.switch:ListenerCanHearSpeaker(speaker, listener)
|
||||
local speakerChar = speaker:GetCharacter()
|
||||
local listeners = self:GetCharacterActiveListeners(speakerChar)
|
||||
if (!istable(listeners)) then
|
||||
-- doubly make sure that the call activity is set correctly on the caller
|
||||
speaker:NotifyLocalized("You are not currently on a phone call!")
|
||||
ErrorNoHaltWithStack("Speaker ("..tostring(speaker:GetName())..") has invalid listener list!")
|
||||
self:ResetCharVars(speakerChar)
|
||||
return false
|
||||
end
|
||||
|
||||
for _, _listener in ipairs(listeners) do
|
||||
if (_listener == listener) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
--[[
|
||||
Some helpers for setting the correct things in the correct order
|
||||
]]
|
||||
|
||||
-- Reset ix.character.landlineConnection variables to default state
|
||||
function ix.phone.switch:ResetCharVars(character)
|
||||
character:SetLandlineConnection({
|
||||
active = false,
|
||||
exchange = nil,
|
||||
extension = nil
|
||||
})
|
||||
end
|
||||
|
||||
-- Set ix.character.landlineConnection variables
|
||||
function ix.phone.switch:SetCharVars(character, bActive, exc, ext)
|
||||
character:SetLandlineConnection({
|
||||
active = bActive,
|
||||
exchange = exc,
|
||||
extension = ext
|
||||
})
|
||||
end
|
||||
|
||||
-- Create a fake destination for testing purposes
|
||||
-- Do nothing if one exists already
|
||||
function ix.phone.switch:initLineTestNumber()
|
||||
if (!self:ExchangeExists(self.lineTestPBX)) then
|
||||
self:AddExchange(self.lineTestPBX)
|
||||
end
|
||||
|
||||
if (!self.lineTestEnt.endpointID) then
|
||||
self.lineTestEnt.endpointID = self.endpoints:Register(self.lineTestEnt)
|
||||
print("Line Test Initalized! EndID: "..tostring(self.lineTestEnt.endpointID))
|
||||
end
|
||||
|
||||
local destination = self:GetDest(self.lineTestPBX, self.lineTestExt)
|
||||
if (!destination) then
|
||||
self:AddDest(self.lineTestPBX, self.lineTestExt, "Line Test", self.lineTestEnt.endpointID)
|
||||
end
|
||||
end
|
||||
|
||||
-- used for debugging purposes (by doing lua_run in rcon)
|
||||
-- calls a specific landline
|
||||
function ix.phone.switch:DebugSinglePartyCall(exchange, ext)
|
||||
if (!self:DestExists(exchange, ext)) then
|
||||
ErrorNoHalt("Destination does not exist!")
|
||||
return -- source does not exist or is not valid
|
||||
end
|
||||
|
||||
self:initLineTestNumber()
|
||||
local connID = self:buildNewConnection()
|
||||
self:buildNewConnectionNode(connID, exchange, ext)
|
||||
self:buildNewConnectionNode(connID, self.lineTestPBX, self.lineTestExt)
|
||||
|
||||
local dest = self:GetDest(exchange, ext)
|
||||
|
||||
if (!istable(dest)) then
|
||||
self:Disconnect(connID) -- source dissapeared for some reason
|
||||
ErrorNoHalt("Destination does not exist, or is invalid!")
|
||||
return
|
||||
end
|
||||
|
||||
print("Destination Endpoint Found!: "..table.ToString(dest, "Destination Endpoint", true))
|
||||
|
||||
local destEnt = self.endpoints:GetEndpoint(tonumber(dest.endID))
|
||||
print("Destination Entity Found! ID: "..tostring(destEnt:EntIndex()))
|
||||
|
||||
destEnt:EnterRing(function(status)
|
||||
if (!status) then -- call did not go through so we need to clean up
|
||||
self:Disconnect(connID)
|
||||
end
|
||||
|
||||
self:NotifyAllListenersOfStatusChange(tonumber(dest.endID), status, status)
|
||||
local client = destEnt.inUseBy
|
||||
net.Start("LineTestChat")
|
||||
net.WriteString("This is a test to determine connection stability. It will automatically disconnect in 10 seconds.")
|
||||
net.Send(client)
|
||||
|
||||
net.Start("LineStatusUpdate")
|
||||
net.WriteString(self.DialStatus.DebugMode)
|
||||
net.Send(client)
|
||||
|
||||
timer.Simple(15, function()
|
||||
net.Start("LineTestChat")
|
||||
net.WriteString("Line test has completed. Disconnecting now.")
|
||||
net.Send(client)
|
||||
|
||||
self:Disconnect(connID)
|
||||
end)
|
||||
end)
|
||||
|
||||
local hangUpCallback = function()
|
||||
-- cleanup
|
||||
self:Disconnect(connID)
|
||||
end
|
||||
|
||||
destEnt.hangUpCallback = hangUpCallback
|
||||
end
|
||||
|
||||
-- used for debugging purposes
|
||||
-- allows landline to make a call out to a test entity placed at map root
|
||||
function ix.phone.switch:StartLineTest(exchange, ext)
|
||||
if (!self:DestExists(exchange, ext)) then
|
||||
ErrorNoHalt("Source does not exist!")
|
||||
return -- source does not exist or is not valid
|
||||
end
|
||||
|
||||
self:initLineTestNumber()
|
||||
local connID = self:BuildNewTwoWayConnection(exchange, ext, self.lineTestPBX, self.lineTestExt)
|
||||
|
||||
local conn = self:GetActiveConnection(exchange, ext)
|
||||
if (!istable(conn)) then
|
||||
ErrorNoHalt("Failed to construct connection nodes! ", tostring(connID))
|
||||
return
|
||||
end
|
||||
|
||||
print("Connection nodes constructed!: "..table.ToString(conn, "ConnID: "..tostring(connID), true))
|
||||
local source = self:GetDest(exchange, ext)
|
||||
|
||||
if (!istable(source)) then
|
||||
self:Disconnect(connID) -- source dissapeared for some reason
|
||||
ErrorNoHalt("Source does not exist, or is invalid!")
|
||||
return
|
||||
end
|
||||
|
||||
print("Source Endpoint Found!: "..table.ToString(source, "Source Endpoint", true))
|
||||
|
||||
local sourceEnt = self.endpoints:GetEndpoint(tonumber(source["endID"]))
|
||||
print("Source Entity Found! ID: "..tostring(sourceEnt:EntIndex()))
|
||||
|
||||
local listeners = self:GetListeners(self.lineTestPBX, self.lineTestExt)
|
||||
local client = listeners[1]
|
||||
if (!client) then
|
||||
self:Disconnect(connID)
|
||||
print("Destination listener pool: "..table.ToString(listeners, "Listener Pool", true))
|
||||
ErrorNoHalt("Destination has no listeners!")
|
||||
return
|
||||
end
|
||||
|
||||
local hangUpCallback = function()
|
||||
-- cleanup
|
||||
self:Disconnect(connID)
|
||||
end
|
||||
|
||||
sourceEnt.hangUpCallback = hangUpCallback
|
||||
|
||||
print("Line Test Listener Found! ID: "..tostring(client))
|
||||
timer.Simple(2, function()
|
||||
net.Start("ixConnectedCallStatusChange")
|
||||
net.WriteBool(true)
|
||||
net.WriteBool(true)
|
||||
net.Send(client)
|
||||
|
||||
net.Start("LineTestChat")
|
||||
net.WriteString("This is a test to determine connection stability. It will automatically disconnect in 10 seconds.")
|
||||
net.Send(client)
|
||||
end)
|
||||
|
||||
timer.Simple(15, function()
|
||||
net.Start("LineTestChat")
|
||||
net.WriteString("Line test has completed. Disconnecting now.")
|
||||
net.Send(client)
|
||||
|
||||
net.Start("ixConnectedCallStatusChange")
|
||||
net.WriteBool(false)
|
||||
net.WriteBool(false)
|
||||
net.Send(client)
|
||||
|
||||
self:Disconnect(connID)
|
||||
end)
|
||||
end
|
||||
Reference in New Issue
Block a user