Advertisement
Guest User

Untitled

a guest
Feb 20th, 2018
418
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 16.02 KB | None | 0 0
  1. local threads = {}
  2. local curThread
  3. local curThreadIndex
  4.  
  5. function Citizen.CreateThread(threadFunction)
  6. table.insert(threads, {
  7. coroutine = coroutine.create(threadFunction),
  8. wakeTime = 0
  9. })
  10. end
  11.  
  12. function Citizen.Wait(msec)
  13. curThread.wakeTime = GetGameTimer() + msec
  14.  
  15. coroutine.yield()
  16. end
  17.  
  18. -- legacy alias (and to prevent people from calling the game's function)
  19. Wait = Citizen.Wait
  20. CreateThread = Citizen.CreateThread
  21.  
  22. function Citizen.CreateThreadNow(threadFunction)
  23. local coro = coroutine.create(threadFunction)
  24.  
  25. local t = {
  26. coroutine = coro,
  27. wakeTime = 0
  28. }
  29.  
  30. -- add new thread and save old thread
  31. local oldThread = curThread
  32. curThread = t
  33.  
  34. local result, err = coroutine.resume(coro)
  35.  
  36. local resumedThread = curThread
  37. -- restore last thread
  38. curThread = oldThread
  39.  
  40. if err then
  41. error('Failed to execute thread: ' .. debug.traceback(coro, err))
  42. end
  43.  
  44. if resumedThread and coroutine.status(coro) ~= 'dead' then
  45. table.insert(threads, t)
  46. end
  47.  
  48. return coroutine.status(coro) ~= 'dead'
  49. end
  50.  
  51. function Citizen.Await(promise)
  52. if not curThread then
  53. error("Current execution context is not in the scheduler, you should use CreateThread / SetTimeout or Event system (AddEventHandler) to be able to Await")
  54. end
  55.  
  56. -- Remove current thread from the pool (avoid resume from the loop)
  57. if curThreadIndex then
  58. table.remove(threads, curThreadIndex)
  59. end
  60.  
  61. curThreadIndex = nil
  62. local resumableThread = curThread
  63.  
  64. promise:next(function (result)
  65. -- Reattach thread
  66. table.insert(threads, resumableThread)
  67.  
  68. curThread = resumableThread
  69. curThreadIndex = #threads
  70.  
  71. local result, err = coroutine.resume(resumableThread.coroutine, result)
  72.  
  73. if err then
  74. error('Failed to resume thread: ' .. debug.traceback(resumableThread.coroutine, err))
  75. end
  76.  
  77. return result
  78. end, function (err)
  79. if err then
  80. Citizen.Trace('Await failure: ' .. debug.traceback(resumableThread.coroutine, err, 2))
  81. end
  82. end)
  83.  
  84. curThread = nil
  85. return coroutine.yield()
  86. end
  87.  
  88. -- SetTimeout
  89. local timeouts = {}
  90.  
  91. function Citizen.SetTimeout(msec, callback)
  92. table.insert(threads, {
  93. coroutine = coroutine.create(callback),
  94. wakeTime = GetGameTimer() + msec
  95. })
  96. end
  97.  
  98. SetTimeout = Citizen.SetTimeout
  99.  
  100. Citizen.SetTickRoutine(function()
  101. local curTime = GetGameTimer()
  102.  
  103. for i = #threads, 1, -1 do
  104. local thread = threads[i]
  105.  
  106. if curTime >= thread.wakeTime then
  107. curThread = thread
  108. curThreadIndex = i
  109.  
  110. local status = coroutine.status(thread.coroutine)
  111.  
  112. if status == 'dead' then
  113. table.remove(threads, i)
  114. else
  115. local result, err = coroutine.resume(thread.coroutine)
  116.  
  117. if not result then
  118. Citizen.Trace("Error resuming coroutine: " .. debug.traceback(thread.coroutine, err) .. "\n")
  119.  
  120. table.remove(threads, i)
  121. end
  122. end
  123. end
  124. end
  125.  
  126. curThread = nil
  127. curThreadIndex = nil
  128. end)
  129.  
  130. local alwaysSafeEvents = {
  131. ["playerDropped"] = true,
  132. ["playerConnecting"] = true
  133. }
  134.  
  135. local eventHandlers = {}
  136. local deserializingNetEvent = false
  137.  
  138. Citizen.SetEventRoutine(function(eventName, eventPayload, eventSource)
  139. -- set the event source
  140. _G.source = eventSource
  141.  
  142. -- try finding an event handler for the event
  143. local eventHandlerEntry = eventHandlers[eventName]
  144.  
  145. if eventHandlerEntry and eventHandlerEntry.handlers then
  146. -- if this is a net event and we don't allow this event to be triggered from the network, return
  147. if eventSource:sub(1, 3) == 'net' then
  148. if not eventHandlerEntry.safeForNet and not alwaysSafeEvents[eventName] then
  149. Citizen.Trace('event ' .. eventName .. " was not safe for net\n")
  150.  
  151. return
  152. end
  153.  
  154. deserializingNetEvent = { source = eventSource }
  155. _G.source = tonumber(eventSource:sub(5))
  156. end
  157.  
  158. -- if we found one, deserialize the data structure
  159. local data = msgpack.unpack(eventPayload)
  160.  
  161. -- return an empty table if the data is nil
  162. if not data then
  163. data = {}
  164. end
  165.  
  166. -- reset serialization
  167. deserializingNetEvent = nil
  168.  
  169. -- if this is a table...
  170. if type(data) == 'table' then
  171. -- loop through all the event handlers
  172. for k, handler in pairs(eventHandlerEntry.handlers) do
  173. Citizen.CreateThreadNow(function()
  174. handler(table.unpack(data))
  175. end)
  176. end
  177. end
  178. end
  179. end)
  180.  
  181. local eventKey = 10
  182.  
  183. function AddEventHandler(eventName, eventRoutine)
  184. local tableEntry = eventHandlers[eventName]
  185.  
  186. if not tableEntry then
  187. tableEntry = { }
  188.  
  189. eventHandlers[eventName] = tableEntry
  190. end
  191.  
  192. if not tableEntry.handlers then
  193. tableEntry.handlers = { }
  194. end
  195.  
  196. eventKey = eventKey + 1
  197. tableEntry.handlers[eventKey] = eventRoutine
  198.  
  199. return {
  200. key = eventKey,
  201. name = eventName
  202. }
  203. end
  204.  
  205. function RemoveEventHandler(eventData)
  206. if not eventData.key and not eventData.name then
  207. error('Invalid event data passed to RemoveEventHandler()')
  208. end
  209.  
  210. -- remove the entry
  211. eventHandlers[eventData.name].handlers[eventData.key] = nil
  212. end
  213.  
  214. function RegisterNetEvent(eventName)
  215. local tableEntry = eventHandlers[eventName]
  216.  
  217. if not tableEntry then
  218. tableEntry = { }
  219.  
  220. eventHandlers[eventName] = tableEntry
  221. end
  222.  
  223. tableEntry.safeForNet = true
  224. end
  225.  
  226. function TriggerEvent(eventName, ...)
  227. local payload = msgpack.pack({...})
  228.  
  229. return TriggerEventInternal(eventName, payload, payload:len())
  230. end
  231.  
  232. if IsDuplicityVersion() then
  233. function TriggerClientEvent(eventName, playerId, ...)
  234. local payload = msgpack.pack({...})
  235.  
  236. return TriggerClientEventInternal(eventName, playerId, payload, payload:len())
  237. end
  238.  
  239. RegisterServerEvent = RegisterNetEvent
  240. RconPrint = Citizen.Trace
  241. GetPlayerEP = GetPlayerEndpoint
  242. RconLog = function() end
  243.  
  244. function GetPlayerIdentifiers(player)
  245. local numIds = GetNumPlayerIdentifiers(player)
  246. local t = {}
  247.  
  248. for i = 0, numIds - 1 do
  249. table.insert(t, GetPlayerIdentifier(player, i))
  250. end
  251.  
  252. return t
  253. end
  254.  
  255. function GetPlayers()
  256. local num = GetNumPlayerIndices()
  257. local t = {}
  258.  
  259. for i = 0, num - 1 do
  260. table.insert(t, GetPlayerFromIndex(i))
  261. end
  262.  
  263. return t
  264. end
  265.  
  266. local httpDispatch = {}
  267. AddEventHandler('__cfx_internal:httpResponse', function(token, status, body, headers)
  268. if httpDispatch[token] then
  269. local userCallback = httpDispatch[token]
  270. httpDispatch[token] = nil
  271. userCallback(status, body, headers)
  272. end
  273. end)
  274.  
  275. function PerformHttpRequest(url, cb, method, data, headers)
  276. local t = {
  277. url = url,
  278. method = method or 'GET',
  279. data = data or '',
  280. headers = headers or {}
  281. }
  282.  
  283. local d = json.encode(t)
  284. local id = PerformHttpRequestInternal(d, d:len())
  285.  
  286. httpDispatch[id] = cb
  287. end
  288. else
  289. function TriggerServerEvent(eventName, ...)
  290. local payload = msgpack.pack({...})
  291.  
  292. return TriggerServerEventInternal(eventName, payload, payload:len())
  293. end
  294. end
  295.  
  296. local funcRefs = {}
  297. local funcRefIdx = 0
  298.  
  299. local function MakeFunctionReference(func)
  300. local thisIdx = funcRefIdx
  301.  
  302. funcRefs[thisIdx] = func
  303.  
  304. funcRefIdx = funcRefIdx + 1
  305.  
  306. return Citizen.CanonicalizeRef(thisIdx)
  307. end
  308.  
  309. function Citizen.GetFunctionReference(func)
  310. if type(func) == 'function' then
  311. return MakeFunctionReference(func)
  312. elseif type(func) == 'table' and rawget(table, '__cfx_functionReference') then
  313. return DuplicateFunctionReference(rawget(table, '__cfx_functionReference'))
  314. end
  315.  
  316. return nil
  317. end
  318.  
  319. Citizen.SetCallRefRoutine(function(refId, argsSerialized)
  320. local ref = funcRefs[refId]
  321.  
  322. if not ref then
  323. Citizen.Trace('Invalid ref call attempt: ' .. refId .. "\n")
  324.  
  325. return msgpack.pack({})
  326. end
  327.  
  328. local err
  329. local retvals
  330. local cb = {}
  331.  
  332. local waited = Citizen.CreateThreadNow(function()
  333. local status, result, error = xpcall(function()
  334. retvals = { ref(table.unpack(msgpack.unpack(argsSerialized))) }
  335. end, debug.traceback)
  336.  
  337. if not status then
  338. err = result
  339. end
  340.  
  341. if cb.cb then
  342. cb.cb(retvals or false, err)
  343. end
  344. end)
  345.  
  346. if not waited then
  347. if err then
  348. error(err)
  349. end
  350.  
  351. return msgpack.pack(retvals)
  352. else
  353. return msgpack.pack({{
  354. __cfx_async_retval = function(rvcb)
  355. cb.cb = rvcb
  356. end
  357. }})
  358. end
  359. end)
  360.  
  361. Citizen.SetDuplicateRefRoutine(function(refId)
  362. local ref = funcRefs[refId]
  363.  
  364. if ref then
  365. local thisIdx = funcRefIdx
  366. funcRefs[thisIdx] = ref
  367.  
  368. funcRefIdx = funcRefIdx + 1
  369.  
  370. return thisIdx
  371. end
  372.  
  373. return -1
  374. end)
  375.  
  376. Citizen.SetDeleteRefRoutine(function(refId)
  377. funcRefs[refId] = nil
  378. end)
  379.  
  380. local EXT_FUNCREF = 10
  381. local EXT_LOCALFUNCREF = 11
  382.  
  383. msgpack.packers['funcref'] = function(buffer, ref)
  384. msgpack.packers['ext'](buffer, EXT_FUNCREF, ref)
  385. end
  386.  
  387. msgpack.packers['table'] = function(buffer, table)
  388. if rawget(table, '__cfx_functionReference') then
  389. -- pack as function reference
  390. msgpack.packers['funcref'](buffer, DuplicateFunctionReference(rawget(table, '__cfx_functionReference')))
  391. else
  392. msgpack.packers['_table'](buffer, table)
  393. end
  394. end
  395.  
  396. msgpack.packers['function'] = function(buffer, func)
  397. msgpack.packers['funcref'](buffer, MakeFunctionReference(func))
  398. end
  399.  
  400. -- RPC REQUEST HANDLER
  401. local InvokeRpcEvent
  402.  
  403. if GetCurrentResourceName() == 'sessionmanager' then
  404. local rpcEvName = ('__cfx_rpcReq')
  405.  
  406. RegisterNetEvent(rpcEvName)
  407.  
  408. AddEventHandler(rpcEvName, function(retEvent, retId, refId, args)
  409. local source = source
  410.  
  411. local eventTriggerFn = TriggerServerEvent
  412.  
  413. if IsDuplicityVersion() then
  414. eventTriggerFn = function(name, ...)
  415. TriggerClientEvent(name, source, ...)
  416. end
  417. end
  418.  
  419. local returnEvent = function(args, err)
  420. eventTriggerFn(retEvent, retId, args, err)
  421. end
  422.  
  423. local function makeArgRefs(o)
  424. if type(o) == 'table' then
  425. for k, v in pairs(o) do
  426. if type(v) == 'table' and rawget(v, '__cfx_functionReference') then
  427. o[k] = function(...)
  428. return InvokeRpcEvent(source, rawget(v, '__cfx_functionReference'), {...})
  429. end
  430. end
  431.  
  432. makeArgRefs(v)
  433. end
  434. end
  435. end
  436.  
  437. makeArgRefs(args)
  438.  
  439. local payload = Citizen.InvokeFunctionReference(refId, msgpack.pack(args))
  440.  
  441. if #payload == 0 then
  442. returnEvent(false, 'err')
  443. return
  444. end
  445.  
  446. local rvs = msgpack.unpack(payload)
  447.  
  448. if type(rvs[1]) == 'table' and rvs[1].__cfx_async_retval then
  449. rvs[1].__cfx_async_retval(returnEvent)
  450. else
  451. returnEvent(rvs)
  452. end
  453. end)
  454. end
  455.  
  456. local rpcId = 0
  457. local rpcPromises = {}
  458. local playerPromises = {}
  459.  
  460. -- RPC REPLY HANDLER
  461. local repName = ('__cfx_rpcRep:%s'):format(GetCurrentResourceName())
  462.  
  463. RegisterNetEvent(repName)
  464.  
  465. AddEventHandler(repName, function(retId, args, err)
  466. local promise = rpcPromises[retId]
  467. rpcPromises[retId] = nil
  468.  
  469. -- remove any player promise for us
  470. for k, v in pairs(playerPromises) do
  471. v[retId] = nil
  472. end
  473.  
  474. if promise then
  475. if args then
  476. promise:resolve(args[1])
  477. elseif err then
  478. promise:reject(err)
  479. end
  480. end
  481. end)
  482.  
  483. if IsDuplicityVersion() then
  484. AddEventHandler('playerDropped', function(reason)
  485. local source = source
  486.  
  487. if playerPromises[source] then
  488. for k, v in pairs(playerPromises[source]) do
  489. local p = rpcPromises[k]
  490.  
  491. if p then
  492. p:reject('Player dropped: ' .. reason)
  493. end
  494. end
  495. end
  496.  
  497. playerPromises[source] = nil
  498. end)
  499. end
  500.  
  501. -- RPC INVOCATION
  502. InvokeRpcEvent = function(source, ref, args)
  503. if not curThread then
  504. error('RPC delegates can only be invoked from a thread.')
  505. end
  506.  
  507. local src = source
  508.  
  509. local eventTriggerFn = TriggerServerEvent
  510.  
  511. if IsDuplicityVersion() then
  512. eventTriggerFn = function(name, ...)
  513. TriggerClientEvent(name, src, ...)
  514. end
  515. end
  516.  
  517. local p = promise.new()
  518. local asyncId = rpcId
  519. rpcId = rpcId + 1
  520.  
  521. local refId = ('%d:%d'):format(GetInstanceId(), asyncId)
  522.  
  523. eventTriggerFn('__cfx_rpcReq', repName, refId, ref, args)
  524.  
  525. -- add rpc promise
  526. rpcPromises[refId] = p
  527.  
  528. -- add a player promise
  529. if not playerPromises[src] then
  530. playerPromises[src] = {}
  531. end
  532.  
  533. playerPromises[src][refId] = true
  534.  
  535. return Citizen.Await(p)
  536. end
  537.  
  538. local funcref_mt = {
  539. __gc = function(t)
  540. DeleteFunctionReference(rawget(t, '__cfx_functionReference'))
  541. end,
  542.  
  543. __index = function(t, k)
  544. error('Cannot index a funcref')
  545. end,
  546.  
  547. __newindex = function(t, k, v)
  548. error('Cannot set indexes on a funcref')
  549. end,
  550.  
  551. __call = function(t, ...)
  552. local netSource = rawget(t, '__cfx_functionSource')
  553. local ref = rawget(t, '__cfx_functionReference')
  554.  
  555. if not netSource then
  556. local args = msgpack.pack({...})
  557.  
  558. -- as Lua doesn't allow directly getting lengths from a data buffer, and _s will zero-terminate, we have a wrapper in the game itself
  559. local rv = Citizen.InvokeFunctionReference(ref, args)
  560. local rvs = msgpack.unpack(rv)
  561.  
  562. -- handle async retvals from refs
  563. if rvs and type(rvs[1]) == 'table' and rawget(rvs[1], '__cfx_async_retval') and curThread then
  564. local p = promise.new()
  565.  
  566. rvs[1].__cfx_async_retval(function(r, e)
  567. if r then
  568. p:resolve(r)
  569. elseif e then
  570. p:reject(e)
  571. end
  572. end)
  573.  
  574. return table.unpack(Citizen.Await(p))
  575. end
  576.  
  577. return table.unpack(rvs)
  578. else
  579. return InvokeRpcEvent(tonumber(netSource.source:sub(5)), ref, {...})
  580. end
  581. end
  582. }
  583.  
  584. msgpack.build_ext = function(tag, data)
  585. if tag == EXT_FUNCREF or tag == EXT_LOCALFUNCREF then
  586. local ref = data
  587.  
  588. local tbl = {
  589. __cfx_functionReference = ref,
  590. __cfx_functionSource = deserializingNetEvent
  591. }
  592.  
  593. if tag == EXT_LOCALFUNCREF then
  594. tbl.__cfx_functionSource = nil
  595. end
  596.  
  597. tbl = setmetatable(tbl, funcref_mt)
  598.  
  599. return tbl
  600. end
  601. end
  602.  
  603. -- exports compatibility
  604. local function getExportEventName(resource, name)
  605. return string.format('__cfx_export_%s_%s', resource, name)
  606. end
  607.  
  608. -- callback cache to avoid extra call to serialization / deserialization process at each time getting an export
  609. local exportsCallbackCache = {}
  610.  
  611. local exportKey = (IsDuplicityVersion() and 'server_export' or 'export')
  612.  
  613. AddEventHandler(('on%sResourceStart'):format(IsDuplicityVersion() and 'Server' or 'Client'), function(resource)
  614. if resource == GetCurrentResourceName() then
  615. local numMetaData = GetNumResourceMetadata(resource, exportKey) or 0
  616.  
  617. for i = 0, numMetaData-1 do
  618. local exportName = GetResourceMetadata(resource, exportKey, i)
  619.  
  620. AddEventHandler(getExportEventName(resource, exportName), function(setCB)
  621. -- get the entry from *our* global table and invoke the set callback
  622. setCB(_G[exportName])
  623. end)
  624. end
  625. end
  626. end)
  627.  
  628. -- Remove cache when resource stop to avoid calling unexisting exports
  629. AddEventHandler(('on%sResourceStop'):format(IsDuplicityVersion() and 'Server' or 'Client'), function(resource)
  630. exportsCallbackCache[resource] = {}
  631. end)
  632.  
  633. -- invocation bit
  634. exports = {}
  635.  
  636. setmetatable(exports, {
  637. __index = function(t, k)
  638. local resource = k
  639.  
  640. return setmetatable({}, {
  641. __index = function(t, k)
  642. if not exportsCallbackCache[resource] then
  643. exportsCallbackCache[resource] = {}
  644. end
  645.  
  646. if not exportsCallbackCache[resource][k] then
  647. TriggerEvent(getExportEventName(resource, k), function(exportData)
  648. exportsCallbackCache[resource][k] = exportData
  649. end)
  650.  
  651. if not exportsCallbackCache[resource][k] then
  652. error('No such export ' .. k .. ' in resource ' .. resource)
  653. end
  654. end
  655.  
  656. return function(self, ...)
  657. local status, result = pcall(exportsCallbackCache[resource][k], ...)
  658.  
  659. if not status then
  660. error('An error happened while calling export ' .. k .. ' of resource ' .. resource .. ' (' .. result .. '), see above for details')
  661. end
  662.  
  663. return result
  664. end
  665. end,
  666.  
  667. __newindex = function(t, k, v)
  668. error('cannot set values on an export resource')
  669. end
  670. })
  671. end,
  672.  
  673. __newindex = function(t, k, v)
  674. error('cannot set values on exports')
  675. end
  676. })
  677.  
  678. -- NUI callbacks
  679. if not IsDuplicityVersion() then
  680. function RegisterNUICallback(type, callback)
  681. RegisterNuiCallbackType(type)
  682.  
  683. AddEventHandler('__cfx_nui:' .. type, function(body, resultCallback)
  684. local status, err = pcall(function()
  685. callback(body, resultCallback)
  686. end)
  687.  
  688. if err then
  689. Citizen.Trace("error during NUI callback " .. type .. ": " .. err .. "\n")
  690. end
  691. end)
  692. end
  693.  
  694. local _sendNuiMessage = SendNuiMessage
  695.  
  696. function SendNUIMessage(message)
  697. _sendNuiMessage(json.encode(message))
  698. end
  699. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement