BigShotDEV

mainfile

Oct 26th, 2020 (edited)
52
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 24.38 KB | None | 0 0
  1. local GetGameTimer = GetGameTimer
  2. local _sbs = Citizen.SubmitBoundaryStart
  3. local coresume, costatus = coroutine.resume, coroutine.status
  4. local debug = debug
  5. local coroutine_close = coroutine.close or (function(c) end) -- 5.3 compatibility
  6. local hadThread = false
  7.  
  8. -- setup msgpack compat
  9. msgpack.set_string('string_compat')
  10. msgpack.set_integer('unsigned')
  11. msgpack.set_array('without_hole')
  12. msgpack.setoption('empty_table_as_array', true)
  13.  
  14. -- setup json compat
  15. json.version = json._VERSION -- Version compatibility
  16. json.setoption("empty_table_as_array", true)
  17. json.setoption('with_hole', true)
  18.  
  19. -- temp
  20. local _in = Citizen.InvokeNative
  21.  
  22. local function FormatStackTrace()
  23. return _in(`FORMAT_STACK_TRACE` & 0xFFFFFFFF, nil, 0, Citizen.ResultAsString())
  24. end
  25.  
  26. local function ProfilerEnterScope(scopeName)
  27. return _in(`PROFILER_ENTER_SCOPE` & 0xFFFFFFFF, scopeName)
  28. end
  29.  
  30. local function ProfilerExitScope()
  31. return _in(`PROFILER_EXIT_SCOPE` & 0xFFFFFFFF)
  32. end
  33.  
  34. local newThreads = {}
  35. local threads = setmetatable({}, {
  36. -- This circumvents undefined behaviour in "next" (and therefore "pairs")
  37. __newindex = newThreads,
  38. -- This is needed for CreateThreadNow to work correctly
  39. __index = newThreads
  40. })
  41.  
  42. local boundaryIdx = 1
  43. local runningThread
  44.  
  45. local function dummyUseBoundary(idx)
  46. return nil
  47. end
  48.  
  49. local function getBoundaryFunc(bfn, bid)
  50. return function(fn, ...)
  51. local boundary = bid or (boundaryIdx + 1)
  52. boundaryIdx = boundaryIdx + 1
  53.  
  54. bfn(boundary, coroutine.running())
  55.  
  56. local wrap = function(...)
  57. dummyUseBoundary(boundary)
  58.  
  59. local v = table.pack(fn(...))
  60. return table.unpack(v)
  61. end
  62.  
  63. local v = table.pack(wrap(...))
  64.  
  65. bfn(boundary, nil)
  66.  
  67. return table.unpack(v)
  68. end
  69. end
  70.  
  71. local runWithBoundaryStart = getBoundaryFunc(Citizen.SubmitBoundaryStart)
  72. local runWithBoundaryEnd = getBoundaryFunc(Citizen.SubmitBoundaryEnd)
  73.  
  74. --[[
  75.  
  76. Thread handling
  77.  
  78. ]]
  79. local function resumeThread(coro) -- Internal utility
  80. if coroutine.status(coro) == "dead" then
  81. threads[coro] = nil
  82. coroutine_close(coro)
  83. return false
  84. end
  85.  
  86. runningThread = coro
  87.  
  88. local thread = threads[coro]
  89.  
  90. if thread then
  91. if thread.name then
  92. ProfilerEnterScope(thread.name)
  93. else
  94. ProfilerEnterScope('thread')
  95. end
  96.  
  97. _sbs(thread.boundary, coro)
  98. end
  99.  
  100. local ok, wakeTimeOrErr = coresume(coro)
  101.  
  102. if ok then
  103. thread = threads[coro]
  104. if thread then
  105. thread.wakeTime = wakeTimeOrErr or 0
  106. hadThread = true
  107. end
  108. else
  109. --Citizen.Trace("Error resuming coroutine: " .. debug.traceback(coro, wakeTimeOrErr) .. "\n")
  110. local fst = FormatStackTrace()
  111.  
  112. if fst then
  113. Citizen.Trace("^1SCRIPT ERROR: " .. wakeTimeOrErr .. "^7\n")
  114. Citizen.Trace(fst)
  115. end
  116. end
  117.  
  118. runningThread = nil
  119.  
  120. ProfilerExitScope()
  121.  
  122. -- Return not finished
  123. return costatus(coro) ~= "dead"
  124. end
  125.  
  126. function Citizen.CreateThread(threadFunction)
  127. local bid = boundaryIdx + 1
  128. boundaryIdx = boundaryIdx + 1
  129.  
  130. local tfn = function()
  131. return runWithBoundaryStart(threadFunction, bid)
  132. end
  133.  
  134. local di = debug.getinfo(threadFunction, 'S')
  135.  
  136. threads[coroutine.create(tfn)] = {
  137. wakeTime = 0,
  138. boundary = bid,
  139. name = ('thread %s[%d..%d]'):format(di.short_src, di.linedefined, di.lastlinedefined)
  140. }
  141.  
  142. hadThread = true
  143. end
  144.  
  145. function Citizen.Wait(msec)
  146. coroutine.yield(GetGameTimer() + msec)
  147. end
  148.  
  149. -- legacy alias (and to prevent people from calling the game's function)
  150. Wait = Citizen.Wait
  151. CreateThread = Citizen.CreateThread
  152.  
  153. function Citizen.CreateThreadNow(threadFunction, name)
  154. local bid = boundaryIdx + 1
  155. boundaryIdx = boundaryIdx + 1
  156.  
  157. local di = debug.getinfo(threadFunction, 'S')
  158. name = name or ('thread_now %s[%d..%d]'):format(di.short_src, di.linedefined, di.lastlinedefined)
  159.  
  160. local tfn = function()
  161. return runWithBoundaryStart(threadFunction, bid)
  162. end
  163.  
  164. local coro = coroutine.create(tfn)
  165. threads[coro] = {
  166. wakeTime = 0,
  167. boundary = bid,
  168. name = name
  169. }
  170.  
  171. return resumeThread(coro)
  172. end
  173.  
  174. function Citizen.Await(promise)
  175. local coro = coroutine.running()
  176. if not coro then
  177. error("Current execution context is not in the scheduler, you should use CreateThread / SetTimeout or Event system (AddEventHandler) to be able to Await")
  178. end
  179.  
  180. -- Indicates if the promise has already been resolved or rejected
  181. -- This is a hack since the API does not expose its state
  182. local isDone = false
  183. local result, err
  184. promise = promise:next(function(...)
  185. isDone = true
  186. result = {...}
  187. end,function(error)
  188. isDone = true
  189. err = error
  190. end)
  191.  
  192. if not isDone then
  193. local threadData = threads[coro]
  194. threads[coro] = nil
  195.  
  196. local function reattach()
  197. threads[coro] = threadData
  198. resumeThread(coro)
  199. end
  200.  
  201. promise:next(reattach, reattach)
  202. Citizen.Wait(0)
  203. end
  204.  
  205. if err then
  206. error(err)
  207. end
  208.  
  209. return table.unpack(result)
  210. end
  211.  
  212. function Citizen.SetTimeout(msec, callback)
  213. local bid = boundaryIdx + 1
  214. boundaryIdx = boundaryIdx + 1
  215.  
  216. local tfn = function()
  217. return runWithBoundaryStart(callback, bid)
  218. end
  219.  
  220. local coro = coroutine.create(tfn)
  221. threads[coro] = {
  222. wakeTime = GetGameTimer() + msec,
  223. boundary = bid
  224. }
  225.  
  226. hadThread = true
  227. end
  228.  
  229. SetTimeout = Citizen.SetTimeout
  230.  
  231. Citizen.SetTickRoutine(function()
  232. if not hadThread then
  233. return
  234. end
  235.  
  236. -- flag to skip thread exec if we don't have any
  237. local thisHadThread = false
  238. local curTime = GetGameTimer()
  239.  
  240. for coro, thread in pairs(newThreads) do
  241. rawset(threads, coro, thread)
  242. newThreads[coro] = nil
  243.  
  244. thisHadThread = true
  245. end
  246.  
  247. for coro, thread in pairs(threads) do
  248. if curTime >= thread.wakeTime then
  249. resumeThread(coro)
  250. end
  251.  
  252. thisHadThread = true
  253. end
  254.  
  255. if not thisHadThread then
  256. hadThread = false
  257. end
  258. end)
  259.  
  260. --[[
  261.  
  262. Event handling
  263.  
  264. ]]
  265.  
  266. local alwaysSafeEvents = {
  267. ["playerDropped"] = true,
  268. ["playerConnecting"] = true
  269. }
  270.  
  271. local eventHandlers = {}
  272. local deserializingNetEvent = false
  273.  
  274. Citizen.SetEventRoutine(function(eventName, eventPayload, eventSource)
  275. -- set the event source
  276. local lastSource = _G.source
  277. _G.source = eventSource
  278.  
  279. -- try finding an event handler for the event
  280. local eventHandlerEntry = eventHandlers[eventName]
  281.  
  282. -- deserialize the event structure (so that we end up adding references to delete later on)
  283. local data = msgpack.unpack(eventPayload)
  284.  
  285. if eventHandlerEntry and eventHandlerEntry.handlers then
  286. -- if this is a net event and we don't allow this event to be triggered from the network, return
  287. if eventSource:sub(1, 3) == 'net' then
  288. if not eventHandlerEntry.safeForNet and not alwaysSafeEvents[eventName] then
  289. Citizen.Trace('event ' .. eventName .. " was not safe for net\n")
  290.  
  291. return
  292. end
  293.  
  294. deserializingNetEvent = { source = eventSource }
  295. _G.source = tonumber(eventSource:sub(5))
  296. end
  297.  
  298. -- return an empty table if the data is nil
  299. if not data then
  300. data = {}
  301. end
  302.  
  303. -- reset serialization
  304. deserializingNetEvent = nil
  305.  
  306. -- if this is a table...
  307. if type(data) == 'table' then
  308. -- loop through all the event handlers
  309. for k, handler in pairs(eventHandlerEntry.handlers) do
  310. local di = debug.getinfo(handler)
  311.  
  312. Citizen.CreateThreadNow(function()
  313. handler(table.unpack(data))
  314. end, ('event %s [%s[%d..%d]]'):format(eventName, di.short_src, di.linedefined, di.lastlinedefined))
  315. end
  316. end
  317. end
  318.  
  319. _G.source = lastSource
  320. end)
  321.  
  322. local stackTraceBoundaryIdx
  323.  
  324. Citizen.SetStackTraceRoutine(function(bs, ts, be, te)
  325. if not ts then
  326. ts = runningThread
  327. end
  328.  
  329. local t
  330. local n = 1
  331.  
  332. local frames = {}
  333. local skip = false
  334.  
  335. if bs then
  336. skip = true
  337. end
  338.  
  339. repeat
  340. if ts then
  341. t = debug.getinfo(ts, n, 'nlfS')
  342. else
  343. t = debug.getinfo(n, 'nlfS')
  344. end
  345.  
  346. if t then
  347. if t.name == 'wrap' and t.source == '@citizen:/scripting/lua/scheduler.lua' then
  348. if not stackTraceBoundaryIdx then
  349. local b, v
  350. local u = 1
  351.  
  352. repeat
  353. b, v = debug.getupvalue(t.func, u)
  354.  
  355. if b == 'boundary' then
  356. break
  357. end
  358.  
  359. u = u + 1
  360. until not b
  361.  
  362. stackTraceBoundaryIdx = u
  363. end
  364.  
  365. local _, boundary = debug.getupvalue(t.func, stackTraceBoundaryIdx)
  366.  
  367. if boundary == bs then
  368. skip = false
  369. end
  370.  
  371. if boundary == be then
  372. break
  373. end
  374. end
  375.  
  376. if not skip then
  377. if t.source and t.source:sub(1, 1) ~= '=' and t.source:sub(1, 10) ~= '@citizen:/' then
  378. table.insert(frames, {
  379. file = t.source:sub(2),
  380. line = t.currentline,
  381. name = t.name or '[global chunk]'
  382. })
  383. end
  384. end
  385.  
  386. n = n + 1
  387. end
  388. until not t
  389.  
  390. return msgpack.pack(frames)
  391. end)
  392.  
  393. local eventKey = 10
  394.  
  395. function AddEventHandler(eventName, eventRoutine)
  396. local tableEntry = eventHandlers[eventName]
  397.  
  398. if not tableEntry then
  399. tableEntry = { }
  400.  
  401. eventHandlers[eventName] = tableEntry
  402. end
  403.  
  404. if not tableEntry.handlers then
  405. tableEntry.handlers = { }
  406. end
  407.  
  408. eventKey = eventKey + 1
  409. tableEntry.handlers[eventKey] = eventRoutine
  410.  
  411. RegisterResourceAsEventHandler(eventName)
  412.  
  413. return {
  414. key = eventKey,
  415. name = eventName
  416. }
  417. end
  418.  
  419. function RemoveEventHandler(eventData)
  420. if not eventData.key and not eventData.name then
  421. error('Invalid event data passed to RemoveEventHandler()')
  422. end
  423.  
  424. -- remove the entry
  425. eventHandlers[eventData.name].handlers[eventData.key] = nil
  426. end
  427.  
  428. function RegisterNetEvent(eventName)
  429. local tableEntry = eventHandlers[eventName]
  430.  
  431. if not tableEntry then
  432. tableEntry = { }
  433.  
  434. eventHandlers[eventName] = tableEntry
  435. end
  436.  
  437. tableEntry.safeForNet = true
  438. end
  439.  
  440. function TriggerEvent(eventName, ...)
  441. local payload = msgpack.pack({...})
  442.  
  443. return runWithBoundaryEnd(function()
  444. return TriggerEventInternal(eventName, payload, payload:len())
  445. end)
  446. end
  447.  
  448. if IsDuplicityVersion() then
  449. function TriggerClientEvent(eventName, playerId, ...)
  450. local payload = msgpack.pack({...})
  451.  
  452. return TriggerClientEventInternal(eventName, playerId, payload, payload:len())
  453. end
  454.  
  455. function TriggerLatentClientEvent(eventName, playerId, bps, ...)
  456. local payload = msgpack.pack({...})
  457.  
  458. return TriggerLatentClientEventInternal(eventName, playerId, payload, payload:len(), tonumber(bps))
  459. end
  460.  
  461. RegisterServerEvent = RegisterNetEvent
  462. RconPrint = Citizen.Trace
  463. GetPlayerEP = GetPlayerEndpoint
  464. RconLog = function() end
  465.  
  466. function GetPlayerIdentifiers(player)
  467. local numIds = GetNumPlayerIdentifiers(player)
  468. local t = {}
  469.  
  470. for i = 0, numIds - 1 do
  471. table.insert(t, GetPlayerIdentifier(player, i))
  472. end
  473.  
  474. return t
  475. end
  476.  
  477. function GetPlayers()
  478. local num = GetNumPlayerIndices()
  479. local t = {}
  480.  
  481. for i = 0, num - 1 do
  482. table.insert(t, GetPlayerFromIndex(i))
  483. end
  484.  
  485. return t
  486. end
  487.  
  488. local httpDispatch = {}
  489. AddEventHandler('__cfx_internal:httpResponse', function(token, status, body, headers)
  490. if httpDispatch[token] then
  491. local userCallback = httpDispatch[token]
  492. httpDispatch[token] = nil
  493. userCallback(status, body, headers)
  494. end
  495. end)
  496.  
  497. function PerformHttpRequest(url, cb, method, data, headers)
  498. local t = {
  499. url = url,
  500. method = method or 'GET',
  501. data = data or '',
  502. headers = headers or {}
  503. }
  504.  
  505. local d = json.encode(t)
  506. local id = PerformHttpRequestInternal(d, d:len())
  507.  
  508. httpDispatch[id] = cb
  509. end
  510. else
  511. function TriggerServerEvent(eventName, ...)
  512. local payload = msgpack.pack({...})
  513.  
  514. return TriggerServerEventInternal(eventName, payload, payload:len())
  515. end
  516.  
  517. function TriggerLatentServerEvent(eventName, bps, ...)
  518. local payload = msgpack.pack({...})
  519.  
  520. return TriggerLatentServerEventInternal(eventName, payload, payload:len(), tonumber(bps))
  521. end
  522. end
  523.  
  524. local funcRefs = {}
  525. local funcRefIdx = 0
  526.  
  527. local function MakeFunctionReference(func)
  528. local thisIdx = funcRefIdx
  529.  
  530. funcRefs[thisIdx] = {
  531. func = func,
  532. refs = 0
  533. }
  534.  
  535. funcRefIdx = funcRefIdx + 1
  536.  
  537. local refStr = Citizen.CanonicalizeRef(thisIdx)
  538. return refStr
  539. end
  540.  
  541. function Citizen.GetFunctionReference(func)
  542. if type(func) == 'function' then
  543. return MakeFunctionReference(func)
  544. elseif type(func) == 'table' and rawget(func, '__cfx_functionReference') then
  545. return MakeFunctionReference(function(...)
  546. return func(...)
  547. end)
  548. end
  549.  
  550. return nil
  551. end
  552.  
  553. local function doStackFormat(err)
  554. local fst = FormatStackTrace()
  555.  
  556. -- already recovering from an error
  557. if not fst then
  558. return nil
  559. end
  560.  
  561. return '^1SCRIPT ERROR: ' .. err .. "^7\n" .. fst
  562. end
  563.  
  564. Citizen.SetCallRefRoutine(function(refId, argsSerialized)
  565. local refPtr = funcRefs[refId]
  566.  
  567. if not refPtr then
  568. Citizen.Trace('Invalid ref call attempt: ' .. refId .. "\n")
  569.  
  570. return msgpack.pack({})
  571. end
  572.  
  573. local ref = refPtr.func
  574.  
  575. local err
  576. local retvals
  577. local cb = {}
  578.  
  579. local di = debug.getinfo(ref)
  580.  
  581. local waited = Citizen.CreateThreadNow(function()
  582. local status, result, error = xpcall(function()
  583. retvals = { ref(table.unpack(msgpack.unpack(argsSerialized))) }
  584. end, doStackFormat)
  585.  
  586. if not status then
  587. err = result or ''
  588. end
  589.  
  590. if cb.cb then
  591. cb.cb(retvals or false, err)
  592. end
  593. end, ('ref call [%s[%d..%d]]'):format(di.short_src, di.linedefined, di.lastlinedefined))
  594.  
  595. if not waited then
  596. if err then
  597. --error(err)
  598. if err ~= '' then
  599. Citizen.Trace(err)
  600. end
  601.  
  602. return msgpack.pack(nil)
  603. end
  604.  
  605. return msgpack.pack(retvals)
  606. else
  607. return msgpack.pack({{
  608. __cfx_async_retval = function(rvcb)
  609. cb.cb = rvcb
  610. end
  611. }})
  612. end
  613. end)
  614.  
  615. Citizen.SetDuplicateRefRoutine(function(refId)
  616. local ref = funcRefs[refId]
  617.  
  618. if ref then
  619. --print(('%s %s ref %d - new refcount %d (from %s)'):format(GetCurrentResourceName(), 'duplicating', refId, ref.refs + 1, GetInvokingResource() or 'nil'))
  620.  
  621. ref.refs = ref.refs + 1
  622.  
  623. return refId
  624. end
  625.  
  626. return -1
  627. end)
  628.  
  629. Citizen.SetDeleteRefRoutine(function(refId)
  630. local ref = funcRefs[refId]
  631.  
  632. if ref then
  633. --print(('%s %s ref %d - new refcount %d (from %s)'):format(GetCurrentResourceName(), 'deleting', refId, ref.refs - 1, GetInvokingResource() or 'nil'))
  634.  
  635. ref.refs = ref.refs - 1
  636.  
  637. if ref.refs <= 0 then
  638. funcRefs[refId] = nil
  639. end
  640. end
  641. end)
  642.  
  643. -- RPC REQUEST HANDLER
  644. local InvokeRpcEvent
  645.  
  646. if GetCurrentResourceName() == 'sessionmanager' then
  647. local rpcEvName = ('__cfx_rpcReq')
  648.  
  649. RegisterNetEvent(rpcEvName)
  650.  
  651. AddEventHandler(rpcEvName, function(retEvent, retId, refId, args)
  652. local source = source
  653.  
  654. local eventTriggerFn = TriggerServerEvent
  655.  
  656. if IsDuplicityVersion() then
  657. eventTriggerFn = function(name, ...)
  658. TriggerClientEvent(name, source, ...)
  659. end
  660. end
  661.  
  662. local returnEvent = function(args, err)
  663. eventTriggerFn(retEvent, retId, args, err)
  664. end
  665.  
  666. local function makeArgRefs(o)
  667. if type(o) == 'table' then
  668. for k, v in pairs(o) do
  669. if type(v) == 'table' and rawget(v, '__cfx_functionReference') then
  670. o[k] = function(...)
  671. return InvokeRpcEvent(source, rawget(v, '__cfx_functionReference'), {...})
  672. end
  673. end
  674.  
  675. makeArgRefs(v)
  676. end
  677. end
  678. end
  679.  
  680. makeArgRefs(args)
  681.  
  682. runWithBoundaryEnd(function()
  683. local payload = Citizen.InvokeFunctionReference(refId, msgpack.pack(args))
  684.  
  685. if #payload == 0 then
  686. returnEvent(false, 'err')
  687. return
  688. end
  689.  
  690. local rvs = msgpack.unpack(payload)
  691.  
  692. if type(rvs[1]) == 'table' and rvs[1].__cfx_async_retval then
  693. rvs[1].__cfx_async_retval(returnEvent)
  694. else
  695. returnEvent(rvs)
  696. end
  697. end)
  698. end)
  699. end
  700.  
  701. local rpcId = 0
  702. local rpcPromises = {}
  703. local playerPromises = {}
  704.  
  705. -- RPC REPLY HANDLER
  706. local repName = ('__cfx_rpcRep:%s'):format(GetCurrentResourceName())
  707.  
  708. RegisterNetEvent(repName)
  709.  
  710. AddEventHandler(repName, function(retId, args, err)
  711. local promise = rpcPromises[retId]
  712. rpcPromises[retId] = nil
  713.  
  714. -- remove any player promise for us
  715. for k, v in pairs(playerPromises) do
  716. v[retId] = nil
  717. end
  718.  
  719. if promise then
  720. if args then
  721. promise:resolve(args[1])
  722. elseif err then
  723. promise:reject(err)
  724. end
  725. end
  726. end)
  727.  
  728. if IsDuplicityVersion() then
  729. AddEventHandler('playerDropped', function(reason)
  730. local source = source
  731.  
  732. if playerPromises[source] then
  733. for k, v in pairs(playerPromises[source]) do
  734. local p = rpcPromises[k]
  735.  
  736. if p then
  737. p:reject('Player dropped: ' .. reason)
  738. end
  739. end
  740. end
  741.  
  742. playerPromises[source] = nil
  743. end)
  744. end
  745.  
  746. local EXT_FUNCREF = 10
  747. local EXT_LOCALFUNCREF = 11
  748.  
  749. msgpack.extend_clear(EXT_FUNCREF, EXT_LOCALFUNCREF)
  750.  
  751. -- RPC INVOCATION
  752. InvokeRpcEvent = function(source, ref, args)
  753. if not coroutine.running() then
  754. error('RPC delegates can only be invoked from a thread.')
  755. end
  756.  
  757. local src = source
  758.  
  759. local eventTriggerFn = TriggerServerEvent
  760.  
  761. if IsDuplicityVersion() then
  762. eventTriggerFn = function(name, ...)
  763. TriggerClientEvent(name, src, ...)
  764. end
  765. end
  766.  
  767. local p = promise.new()
  768. local asyncId = rpcId
  769. rpcId = rpcId + 1
  770.  
  771. local refId = ('%d:%d'):format(GetInstanceId(), asyncId)
  772.  
  773. eventTriggerFn('__cfx_rpcReq', repName, refId, ref, args)
  774.  
  775. -- add rpc promise
  776. rpcPromises[refId] = p
  777.  
  778. -- add a player promise
  779. if not playerPromises[src] then
  780. playerPromises[src] = {}
  781. end
  782.  
  783. playerPromises[src][refId] = true
  784.  
  785. return Citizen.Await(p)
  786. end
  787.  
  788. local funcref_mt = nil
  789.  
  790. funcref_mt = msgpack.extend({
  791. __gc = function(t)
  792. DeleteFunctionReference(rawget(t, '__cfx_functionReference'))
  793. end,
  794.  
  795. __index = function(t, k)
  796. error('Cannot index a funcref')
  797. end,
  798.  
  799. __newindex = function(t, k, v)
  800. error('Cannot set indexes on a funcref')
  801. end,
  802.  
  803. __call = function(t, ...)
  804. local netSource = rawget(t, '__cfx_functionSource')
  805. local ref = rawget(t, '__cfx_functionReference')
  806.  
  807. if not netSource then
  808. local args = msgpack.pack({...})
  809.  
  810. -- 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
  811. local rv = runWithBoundaryEnd(function()
  812. return Citizen.InvokeFunctionReference(ref, args)
  813. end)
  814. local rvs = msgpack.unpack(rv)
  815.  
  816. -- handle async retvals from refs
  817. if rvs and type(rvs[1]) == 'table' and rawget(rvs[1], '__cfx_async_retval') and coroutine.running() then
  818. local p = promise.new()
  819.  
  820. rvs[1].__cfx_async_retval(function(r, e)
  821. if r then
  822. p:resolve(r)
  823. elseif e then
  824. p:reject(e)
  825. end
  826. end)
  827.  
  828. return table.unpack(Citizen.Await(p))
  829. end
  830.  
  831. return table.unpack(rvs)
  832. else
  833. return InvokeRpcEvent(tonumber(netSource.source:sub(5)), ref, {...})
  834. end
  835. end,
  836.  
  837. __ext = EXT_FUNCREF,
  838.  
  839. __pack = function(self, tag)
  840. local refstr = Citizen.GetFunctionReference(self)
  841. if refstr then
  842. return refstr
  843. else
  844. error(("Unknown funcref type: %d %s"):format(tag, type(self)))
  845. end
  846. end,
  847.  
  848. __unpack = function(data, tag)
  849. local ref = data
  850.  
  851. -- add a reference
  852. DuplicateFunctionReference(ref)
  853.  
  854. local tbl = {
  855. __cfx_functionReference = ref,
  856. __cfx_functionSource = deserializingNetEvent
  857. }
  858.  
  859. if tag == EXT_LOCALFUNCREF then
  860. tbl.__cfx_functionSource = nil
  861. end
  862.  
  863. tbl = setmetatable(tbl, funcref_mt)
  864.  
  865. return tbl
  866. end,
  867. })
  868.  
  869. --[[ Also initialize unpackers for local function references --]]
  870. msgpack.extend({
  871. __ext = EXT_LOCALFUNCREF,
  872. __pack = funcref_mt.__pack,
  873. __unpack = funcref_mt.__unpack,
  874. })
  875.  
  876. msgpack.settype("function", EXT_FUNCREF)
  877.  
  878. -- exports compatibility
  879. local function getExportEventName(resource, name)
  880. return string.format('__cfx_export_%s_%s', resource, name)
  881. end
  882.  
  883. -- callback cache to avoid extra call to serialization / deserialization process at each time getting an export
  884. local exportsCallbackCache = {}
  885.  
  886. local exportKey = (IsDuplicityVersion() and 'server_export' or 'export')
  887.  
  888. do
  889. local resource = GetCurrentResourceName()
  890.  
  891. local numMetaData = GetNumResourceMetadata(resource, exportKey) or 0
  892.  
  893. for i = 0, numMetaData-1 do
  894. local exportName = GetResourceMetadata(resource, exportKey, i)
  895.  
  896. AddEventHandler(getExportEventName(resource, exportName), function(setCB)
  897. -- get the entry from *our* global table and invoke the set callback
  898. if _G[exportName] then
  899. setCB(_G[exportName])
  900. end
  901. end)
  902. end
  903. end
  904.  
  905. -- Remove cache when resource stop to avoid calling unexisting exports
  906. local function lazyEventHandler() -- lazy initializer so we don't add an event we don't need
  907. AddEventHandler(('on%sResourceStop'):format(IsDuplicityVersion() and 'Server' or 'Client'), function(resource)
  908. exportsCallbackCache[resource] = {}
  909. end)
  910.  
  911. lazyEventHandler = function() end
  912. end
  913.  
  914. -- invocation bit
  915. exports = {}
  916.  
  917. setmetatable(exports, {
  918. __index = function(t, k)
  919. local resource = k
  920.  
  921. return setmetatable({}, {
  922. __index = function(t, k)
  923. lazyEventHandler()
  924.  
  925. if not exportsCallbackCache[resource] then
  926. exportsCallbackCache[resource] = {}
  927. end
  928.  
  929. if not exportsCallbackCache[resource][k] then
  930. TriggerEvent(getExportEventName(resource, k), function(exportData)
  931. exportsCallbackCache[resource][k] = exportData
  932. end)
  933.  
  934. if not exportsCallbackCache[resource][k] then
  935. error('No such export ' .. k .. ' in resource ' .. resource)
  936. end
  937. end
  938.  
  939. return function(self, ...)
  940. local status, result = pcall(exportsCallbackCache[resource][k], ...)
  941.  
  942. if not status then
  943. error('An error happened while calling export ' .. k .. ' of resource ' .. resource .. ' (' .. result .. '), see above for details')
  944. end
  945.  
  946. return result
  947. end
  948. end,
  949.  
  950. __newindex = function(t, k, v)
  951. error('cannot set values on an export resource')
  952. end
  953. })
  954. end,
  955.  
  956. __newindex = function(t, k, v)
  957. error('cannot set values on exports')
  958. end,
  959.  
  960. __call = function(t, exportName, func)
  961. AddEventHandler(getExportEventName(GetCurrentResourceName(), exportName), function(setCB)
  962. setCB(func)
  963. end)
  964. end
  965. })
  966.  
  967. -- NUI callbacks
  968. if not IsDuplicityVersion() then
  969. function RegisterNUICallback(type, callback)
  970. RegisterNuiCallbackType(type)
  971.  
  972. AddEventHandler('__cfx_nui:' .. type, function(body, resultCallback)
  973. local status, err = pcall(function()
  974. callback(body, resultCallback)
  975. end)
  976.  
  977. if err then
  978. Citizen.Trace("error during NUI callback " .. type .. ": " .. err .. "\n")
  979. end
  980. end)
  981. end
  982.  
  983. local _sendNuiMessage = SendNuiMessage
  984.  
  985. function SendNUIMessage(message)
  986. _sendNuiMessage(json.encode(message))
  987. end
  988. end
  989.  
  990. -- entity helpers
  991. local EXT_ENTITY = 41
  992. local EXT_PLAYER = 42
  993.  
  994. msgpack.extend_clear(EXT_ENTITY, EXT_PLAYER)
  995.  
  996. local function NewStateBag(es)
  997. local sv = IsDuplicityVersion()
  998.  
  999. return setmetatable({}, {
  1000. __index = function(_, s)
  1001. if s == 'set' then
  1002. return function(_, s, v, r)
  1003. local payload = msgpack.pack(v)
  1004. SetStateBagValue(es, s, payload, payload:len(), r)
  1005. end
  1006. end
  1007.  
  1008. return GetStateBagValue(es, s)
  1009. end,
  1010.  
  1011. __newindex = function(_, s, v)
  1012. local payload = msgpack.pack(v)
  1013. SetStateBagValue(es, s, payload, payload:len(), sv)
  1014. end
  1015. })
  1016. end
  1017.  
  1018. GlobalState = NewStateBag('global')
  1019.  
  1020. local entityTM = {
  1021. __index = function(t, s)
  1022. if s == 'state' then
  1023. local es = ('entity:%d'):format(NetworkGetNetworkIdFromEntity(t.__data))
  1024.  
  1025. if IsDuplicityVersion() then
  1026. EnsureEntityStateBag(t.__data)
  1027. end
  1028.  
  1029. return NewStateBag(es)
  1030. end
  1031.  
  1032. return nil
  1033. end,
  1034.  
  1035. __newindex = function()
  1036. error('Not allowed at this time.')
  1037. end,
  1038.  
  1039. __ext = EXT_ENTITY,
  1040.  
  1041. __pack = function(self, t)
  1042. return tostring(NetworkGetNetworkIdFromEntity(self.__data))
  1043. end,
  1044.  
  1045. __unpack = function(data, t)
  1046. local ref = NetworkGetEntityFromNetworkId(tonumber(data))
  1047.  
  1048. return setmetatable({
  1049. __data = ref
  1050. }, entityTM)
  1051. end
  1052. }
  1053.  
  1054. msgpack.extend(entityTM)
  1055.  
  1056. local playerTM = {
  1057. __index = function(t, s)
  1058. if s == 'state' then
  1059. local pid = t.__data
  1060.  
  1061. if pid == -1 then
  1062. pid = GetPlayerServerId(PlayerId())
  1063. end
  1064.  
  1065. local es = ('player:%d'):format(pid)
  1066.  
  1067. return NewStateBag(es)
  1068. end
  1069.  
  1070. return nil
  1071. end,
  1072.  
  1073. __newindex = function()
  1074. error('Not allowed at this time.')
  1075. end,
  1076.  
  1077. __ext = EXT_PLAYER,
  1078.  
  1079. __pack = function(self, t)
  1080. return tostring(self.__data)
  1081. end,
  1082.  
  1083. __unpack = function(data, t)
  1084. local ref = tonumber(data)
  1085.  
  1086. return setmetatable({
  1087. __data = ref
  1088. }, playerTM)
  1089. end
  1090. }
  1091.  
  1092. msgpack.extend(playerTM)
  1093.  
  1094. function Entity(ent)
  1095. if type(ent) == 'number' then
  1096. return setmetatable({
  1097. __data = ent
  1098. }, entityTM)
  1099. end
  1100.  
  1101. return ent
  1102. end
  1103.  
  1104. function Player(ent)
  1105. if type(ent) == 'number' or type(ent) == 'string' then
  1106. return setmetatable({
  1107. __data = tonumber(ent)
  1108. }, playerTM)
  1109. end
  1110.  
  1111. return ent
  1112. end
  1113.  
  1114. if not IsDuplicityVersion() then
  1115. LocalPlayer = Player(-1)
  1116. end
Add Comment
Please, Sign In to add comment