├── server ├── exports │ ├── events.lua │ └── info.lua ├── default_events.lua ├── system │ ├── cooldown.lua │ ├── events.lua │ └── lobby.lua ├── main.lua └── module │ └── arena.lua ├── .gitattributes ├── fxmanifest.lua ├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── html ├── css │ ├── style.css │ └── reset.css ├── scripts │ └── listener.js └── index.html ├── client ├── exports │ ├── events.lua │ └── info.lua ├── events.lua ├── client.lua └── system │ └── events.lua ├── config.lua ├── LICENSE └── readme.md /server/exports/events.lua: -------------------------------------------------------------------------------- 1 | exports("On", On) -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /fxmanifest.lua: -------------------------------------------------------------------------------- 1 | fx_version 'adamant' 2 | games { 'gta5' } 3 | 4 | client_scripts { 5 | "client/system/*.lua", 6 | "client/exports/*.lua", 7 | "client/*.lua", 8 | } 9 | 10 | server_script { 11 | "server/main.lua", 12 | "server/default_events.lua", 13 | "server/exports/*.lua", 14 | "server/module/*.lua", 15 | "server/system/*.lua", 16 | } 17 | 18 | shared_scripts { 19 | "config.lua", 20 | } 21 | 22 | files { 23 | "html/*.html", 24 | "html/css/*.css", 25 | "html/scripts/*.js", 26 | } 27 | 28 | ui_page "html/index.html" -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Additional context** 27 | Add any other context about the problem here. 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /html/css/style.css: -------------------------------------------------------------------------------- 1 | *{ 2 | color: black; 3 | user-select: none; /* supported by Chrome and Opera */ 4 | -webkit-user-select: none; /* Safari */ 5 | -khtml-user-select: none; /* Konqueror HTML */ 6 | -moz-user-select: none; /* Firefox */ 7 | -ms-user-select: none; /* Internet Explorer/Edge */ 8 | } 9 | 10 | body { 11 | font-family: 'Montserrat', sans-serif; 12 | background: url(../Screenshot_2.png); 13 | background-repeat: no-repeat; 14 | background-size: 100% 100%; 15 | } 16 | 17 | i{ 18 | color: white; 19 | } 20 | 21 | .box{ 22 | background: #0000009e; 23 | color: white; 24 | text-align: left; 25 | padding-right: 9px; 26 | padding-top: 5px; 27 | padding-bottom: 5px; 28 | padding-left: 5px; 29 | } -------------------------------------------------------------------------------- /client/exports/events.lua: -------------------------------------------------------------------------------- 1 | exports("On", On) 2 | 3 | -- will register callback for this event 4 | function OnArenaRoundEnd(arena, cb) 5 | On(arena, "roundend", cb) 6 | end 7 | 8 | exports("OnArenaRoundEnd", OnArenaRoundEnd) 9 | 10 | -- will register callback for this event 11 | function OnPlayerJoinLobby(arena, cb) 12 | On(arena, "join", cb) 13 | end 14 | 15 | exports("OnPlayerJoinLobby", OnPlayerJoinLobby) 16 | 17 | -- will register callback for this event 18 | function OnPlayerExitLobby(arena, cb) 19 | On(arena, "leave", cb) 20 | end 21 | 22 | exports("OnPlayerExitLobby", OnPlayerExitLobby) 23 | 24 | -- will register callback for this event 25 | function OnArenaStart(arena, cb) 26 | On(arena, "start", cb) 27 | end 28 | 29 | exports("OnArenaStart", OnArenaStart) 30 | 31 | -- will register callback for this event 32 | function OnArenaEnd(arena, cb) 33 | On(arena, "end", cb) 34 | end 35 | 36 | exports("OnArenaEnd", OnArenaEnd) -------------------------------------------------------------------------------- /html/scripts/listener.js: -------------------------------------------------------------------------------- 1 | $(function(){ 2 | function display(bool) { 3 | if (bool) { 4 | $("#body").show(); 5 | } else { 6 | $("#body").hide(); 7 | } 8 | } 9 | display(false); 10 | 11 | window.addEventListener('message', function(event) { 12 | var item = event.data; 13 | if (item.type === "ui"){ 14 | display(item.status); 15 | $("#seconds").text("Waiting for people"); 16 | } 17 | 18 | if (item.type === "arenaName"){ 19 | $("#arenaName").text(item.arenaName); 20 | } 21 | 22 | if (item.type === "updateTime"){ 23 | $("#seconds").text("Wait please: "+ item.time +" seconds"); 24 | } 25 | 26 | if (item.type === "playerNameList"){ 27 | $("#players").text(""); 28 | for (var index in item.Names) { 29 | $("#players").append("
" + item.Names[index] + "
"); 30 | } 31 | } 32 | }) 33 | 34 | }); -------------------------------------------------------------------------------- /server/default_events.lua: -------------------------------------------------------------------------------- 1 | -- When player leave the game we will detele his instance/remove him from arena he is playing 2 | AddEventHandler("playerDropped", function() 3 | local arenaID = PlayerInfo[source] 4 | if arenaID and arenaID ~= "none" then 5 | CreateArena(arenaID).RemovePlayer(source) 6 | end 7 | CooldownPlayers[source] = nil 8 | end) 9 | 10 | -- When player client side load we will write his ID + basic stuff into predefined variables in main 11 | RegisterNetEvent("ArenaAPI:PlayerJoinedFivem") 12 | AddEventHandler("ArenaAPI:PlayerJoinedFivem", function() 13 | TriggerClientEvent("ArenaAPI:sendStatus", source, "updateData", ArenaList) 14 | PlayerInfo[source] = "none" 15 | CooldownPlayers[source] = { } 16 | end) 17 | 18 | -- When some resource will stop it will delete all related events to the resource so it doesnt get 19 | -- duplicated if the resource was only reseted due to testing 20 | AddEventHandler('onResourceStop', function(resourceName) 21 | RemoveEventsWithNameResource(resourceName) 22 | end) -------------------------------------------------------------------------------- /html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
Derby #01
15 |
Waiting for people
16 |
17 | 18 |
19 |
20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /server/system/cooldown.lua: -------------------------------------------------------------------------------- 1 | -- Will set a cooldown to player so he cannot join the lobby defined in args 2 | --- @param source int 3 | --- @param arena string 4 | --- @param time int 5 | function CooldownPlayer(source, arena, time) 6 | CooldownPlayers[source][arena] = os.time(os.date("!*t")) + time 7 | end 8 | 9 | -- Will return true/false if player has cooldown to join the defined lobby 10 | --- @param source int 11 | --- @param arena string 12 | function IsPlayerInCooldown(source, arena) 13 | if CooldownPlayers[source][arena] == nil then return false end 14 | return CooldownPlayers[source][arena] > os.time(os.date("!*t")) 15 | end 16 | 17 | -- Will convert time into hh:mm:ss 18 | --- @param time int 19 | function TimestampToString(time) 20 | return os.date( "%H:%M:%S", time + Config.TimeZone * 60 * 60 ) 21 | end 22 | 23 | -- Will return timestamp 24 | --- @param source int 25 | --- @param arena string 26 | function GetcooldownForPlayer(source, arena) 27 | if CooldownPlayers[source][arena] == nil then return os.time(os.date("!*t")) end 28 | return CooldownPlayers[source][arena] 29 | end -------------------------------------------------------------------------------- /config.lua: -------------------------------------------------------------------------------- 1 | Config = {} 2 | 3 | -- Message list 4 | Config.MessageList = { 5 | ["arena_doesnt_exists"] = "The arena doesnt exists", 6 | ["player_isnt_in_arena"] = "You cant leave any arena because you are not in any arena", 7 | ["player_in_arena"] = "You cant join any arena, first you need to leave the current arena", 8 | ["arena_joined"] = "You joined arena, wait till the game will be ready", 9 | ["arena_left"] = "You left arena, you dont need to wait anymore for anything.", 10 | ["maximum_people"] = "This arena is at it maximum capacity!", 11 | ["cant_acces_this_arena"] = "You cant acces this arena, this arena is privte.", 12 | ["arena_busy"] = "This arena is busy, you have to wait until the arena is finished playing.", 13 | ["cooldown_to_join"] = "You need to wait before joining to this arena! Wait till %s to join!", 14 | } 15 | 16 | -- your current time zone 17 | Config.TimeZone = 1 18 | 19 | -- How many seconds player will have to wait before trying to join same lobby after leaving ? 20 | -- This will prevent trollers from trying to stop the lobby start. 21 | Config.TimeCooldown = 25 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 MrXogos 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /html/css/reset.css: -------------------------------------------------------------------------------- 1 | /* http://meyerweb.com/eric/tools/css/reset/ 2 | v2.0 | 20110126 3 | License: none (public domain) 4 | */ 5 | 6 | html, body, div, span, applet, object, iframe, 7 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 8 | a, abbr, acronym, address, big, cite, code, 9 | del, dfn, em, img, ins, kbd, q, s, samp, 10 | small, strike, strong, sub, sup, tt, var, 11 | b, u, i, center, 12 | dl, dt, dd, ol, ul, li, 13 | fieldset, form, label, legend, 14 | table, caption, tbody, tfoot, thead, tr, th, td, 15 | article, aside, canvas, details, embed, 16 | figure, figcaption, footer, header, hgroup, 17 | menu, nav, output, ruby, section, summary, 18 | time, mark, audio, video { 19 | margin: 0; 20 | padding: 0; 21 | border: 0; 22 | font-size: 100%; 23 | font: inherit; 24 | vertical-align: baseline; 25 | } 26 | /* HTML5 display-role reset for older browsers */ 27 | article, aside, details, figcaption, figure, 28 | footer, header, hgroup, menu, nav, section { 29 | display: block; 30 | } 31 | body { 32 | line-height: 1; 33 | } 34 | ol, ul { 35 | list-style: none; 36 | } 37 | blockquote, q { 38 | quotes: none; 39 | } 40 | blockquote:before, blockquote:after, 41 | q:before, q:after { 42 | content: ''; 43 | content: none; 44 | } 45 | table { 46 | border-collapse: collapse; 47 | border-spacing: 0; 48 | } -------------------------------------------------------------------------------- /client/events.lua: -------------------------------------------------------------------------------- 1 | -- When some resource will stop it will delete all related events to the resource so it doesnt get 2 | -- duplicated if the resource was only reseted due to testing 3 | AddEventHandler('onResourceStop', function(resourceName) 4 | RemoveEventsWithNameResource(resourceName) 5 | end) 6 | 7 | -- will fetch info from server and save it into client variable 8 | RegisterNetEvent("ArenaAPI:sendStatus") 9 | AddEventHandler("ArenaAPI:sendStatus", function(type, data) 10 | local arena = data.ArenaIdentifier 11 | if type == "updateData" then 12 | ArenaData = data 13 | UpdatePlayerNameList() 14 | end 15 | 16 | if type == "roundEnd" then 17 | if ArenaData[arena].MaximumArenaTime then 18 | ArenaData[arena].MaximumArenaTime = data.MaximumLobbyTime + 1 19 | end 20 | CallOn(arena, "roundend", data) 21 | end 22 | 23 | if type == "start" then 24 | CallOn(arena, "start", data) 25 | if PlayerData.CurrentArena == arena then 26 | IsArenaBusy = true 27 | end 28 | end 29 | 30 | if type == "end" then 31 | CallOn(arena, "end", data) 32 | if ArenaData[arena].MaximumArenaTime then 33 | ArenaData[arena].MaximumArenaTime = data.MaximumLobbyTime + 1 34 | end 35 | if PlayerData.CurrentArena == arena then 36 | IsArenaBusy = false 37 | end 38 | PlayerData.CurrentArena = "none" 39 | end 40 | 41 | if type == "join" then 42 | PlayerData.CurrentArena = data.ArenaIdentifier 43 | CallOn(arena, "join", data) 44 | 45 | SendNUIMessage({ type = "ui", status = true, }) 46 | SendNUIMessage({ type = "arenaName", arenaName = data.ArenaLabel }) 47 | UpdatePlayerNameList() 48 | end 49 | 50 | if type == "leave" then 51 | CallOn(arena, "leave", data) 52 | 53 | if PlayerData.CurrentArena == arena then 54 | IsArenaBusy = false 55 | end 56 | 57 | PlayerData.CurrentArena = "none" 58 | SendNUIMessage({ type = "ui", status = false, }) 59 | end 60 | end) -------------------------------------------------------------------------------- /server/exports/info.lua: -------------------------------------------------------------------------------- 1 | -- Will return array with arenas list 2 | function GetArenaList() 3 | return ArenaList 4 | end 5 | 6 | exports("GetArenaList", GetArenaList) 7 | 8 | -- Return true/false if the key exists in variable "ArenaList" 9 | --- @param identifier string 10 | function DoesArenaExists(identifier) 11 | return ArenaList[identifier] ~= nil 12 | end 13 | 14 | exports("DoesArenaExists", DoesArenaExists) 15 | 16 | -- Return true/false if player is in any lobby/Arena 17 | --- @param identifier string 18 | function IsPlayerInAnyArena(source) 19 | return PlayerInfo[source] ~= "none" 20 | end 21 | 22 | exports("IsPlayerInAnyArena", IsPlayerInAnyArena) 23 | 24 | -- will return true/false if player is in the arena defined in arguments 25 | --- @param identifier string 26 | function IsPlayerInArena(source, arena) 27 | return PlayerInfo[source] == arena 28 | end 29 | 30 | exports("IsPlayerInArena", IsPlayerInArena) 31 | 32 | -- Will return player arena name 33 | --- @param identifier string 34 | function GetPlayerArena(source) 35 | return PlayerInfo[source] 36 | end 37 | 38 | exports("GetPlayerArena", GetPlayerArena) 39 | 40 | -- Will return true/false if arena is busy 41 | --- @param identifier string 42 | function IsArenaBusy(identifier) 43 | return ArenaList[identifier].ArenaState == "ArenaBusy" 44 | end 45 | 46 | exports("IsArenaBusy", IsArenaBusy) 47 | 48 | -- Will return player count in the arena/lobby 49 | --- @param identifier string 50 | function GetPlayerCount(identifier) 51 | return ArenaList[identifier].CurrentCapacity 52 | end 53 | 54 | exports("GetPlayerCount", GetPlayerCount) 55 | 56 | -- Will return true/false if arena is active 57 | --- @param identifier string 58 | function IsArenaActive(identifier) 59 | return ArenaList[identifier].ArenaState == "ArenaActive" 60 | end 61 | 62 | exports("IsArenaActive", IsArenaActive) 63 | 64 | -- Will return true/false if arena is inactive 65 | --- @param identifier string 66 | function IsArenaInactive (identifier) 67 | return ArenaList[identifier].ArenaState == "ArenaInactive" 68 | end 69 | 70 | exports("IsArenaInactive", IsArenaInactive) 71 | 72 | -- Will return string in what state is the arena 73 | --- @param identifier string 74 | function GetArenaState (identifier) 75 | return ArenaList[identifier].ArenaState 76 | end 77 | 78 | exports("GetArenaState", GetArenaState) -------------------------------------------------------------------------------- /client/exports/info.lua: -------------------------------------------------------------------------------- 1 | -- Will return array of the arena name 2 | --- @param identifier string 3 | function GetArena(identifier) 4 | return ArenaData[identifier] 5 | end 6 | 7 | exports("GetArena", GetArena) 8 | 9 | -- Will return true/false if player is in any arena 10 | function IsPlayerInAnyArena() 11 | return PlayerData.CurrentArena ~= "none" 12 | end 13 | 14 | exports("IsPlayerInAnyArena", IsPlayerInAnyArena) 15 | 16 | -- will return player arena name 17 | function GetPlayerArena() 18 | return PlayerData.CurrentArena 19 | end 20 | 21 | exports("GetPlayerArena", GetPlayerArena) 22 | 23 | -- Will return true/false if the player is in specific arena 24 | --- @param arena string 25 | function IsPlayerInArena(arena) 26 | return PlayerData.CurrentArena == arena 27 | end 28 | 29 | exports("IsPlayerInArena", IsPlayerInArena) 30 | 31 | -- will return label of the arena 32 | --- @param identifier string 33 | function GetArenaLabel(identifier) 34 | return GetCurrentArenaData(identifier).ArenaLabel 35 | end 36 | 37 | exports("GetArenaLabel", GetArenaLabel) 38 | 39 | -- Will return how many players can be in the specific arena 40 | --- @param identifier string 41 | function GetArenaMaximumSize(identifier) 42 | return GetCurrentArenaData(identifier).MaximumCapacity 43 | end 44 | 45 | exports("GetArenaMaximumSize", GetArenaMaximumSize) 46 | 47 | -- Will return minimum required people to start arena 48 | --- @param identifier string 49 | function GetArenaMinimumSize(identifier) 50 | return GetCurrentArenaData(identifier).MinimumCapacity 51 | end 52 | 53 | exports("GetArenaMinimumSize", GetArenaMinimumSize) 54 | 55 | -- Will return how many people is in this specific arena 56 | --- @param identifier string 57 | function GetArenaCurrentSize(identifier) 58 | return GetCurrentArenaData(identifier).CurrentCapacity 59 | end 60 | 61 | exports("GetArenaCurrentSize", GetArenaCurrentSize) 62 | 63 | -- will return data for the arena 64 | --- @param identifier string 65 | function GetCurrentArenaData(identifier) 66 | return { 67 | ArenaIdentifier = ArenaData[identifier].ArenaIdentifier, 68 | ArenaLabel = ArenaData[identifier].ArenaLabel, 69 | MaximumCapacity = ArenaData[identifier].MaximumCapacity, 70 | MinimumCapacity = ArenaData[identifier].MinimumCapacity, 71 | CurrentCapacity = ArenaData[identifier].CurrentCapacity, 72 | } 73 | end 74 | 75 | exports("GetCurrentArenaData", GetCurrentArenaData) -------------------------------------------------------------------------------- /client/client.lua: -------------------------------------------------------------------------------- 1 | ---------------------------------------- 2 | --- Variables 3 | ---------------------------------------- 4 | IsArenaBusy = false 5 | 6 | ArenaData = {} 7 | PlayerData = { 8 | CurrentArena = "none", 9 | } 10 | ---------------------------------------- 11 | --- Functions 12 | ---------------------------------------- 13 | -- stolen from https://scriptinghelpers.org/questions/43622/how-do-i-turn-seconds-to-minutes-and-seconds 14 | function DecimalsToMinutes(dec) 15 | local ms = tonumber(dec) 16 | return math.floor(ms / 60) .. ":" .. (ms % 60) 17 | end 18 | 19 | function UpdatePlayerNameList() 20 | if IsPlayerInAnyArena() then 21 | local arena = GetPlayerArena() 22 | local data = GetArena(arena) 23 | local names = {} 24 | for k, v in pairs(data.PlayerNameList) do 25 | table.insert(names, v) 26 | end 27 | SendNUIMessage({ type = "playerNameList", Names = names, }) 28 | end 29 | end 30 | ---------------------------------------- 31 | --- threads 32 | ---------------------------------------- 33 | CreateThread(function() 34 | TriggerServerEvent("ArenaAPI:PlayerJoinedFivem") 35 | end) 36 | 37 | CreateThread(function() 38 | while true do 39 | Wait(1000) 40 | if IsArenaBusy then 41 | local arena = GetPlayerArena() 42 | local data = GetArena(arena) 43 | if data.MaximumArenaTime ~= nil and data.MaximumArenaTime > 1 then 44 | data.MaximumArenaTime = data.MaximumArenaTime - 1 45 | BeginTextCommandPrint('STRING') 46 | AddTextComponentSubstringPlayerName(DecimalsToMinutes(data.MaximumArenaTime) .. " time left") 47 | EndTextCommandPrint(1000, 1) 48 | end 49 | end 50 | 51 | if IsPlayerInAnyArena() then 52 | local arena = GetPlayerArena() 53 | local data = GetArena(arena) 54 | 55 | if data.MinimumCapacity - 1 < data.CurrentCapacity then 56 | if data.MaximumLobbyTime == 1 then 57 | SendNUIMessage({ type = "ui", status = false, }) 58 | else 59 | data.MaximumLobbyTime = data.MaximumLobbyTime - 1 60 | 61 | SendNUIMessage({ 62 | type = "updateTime", 63 | time = data.MaximumLobbyTime, 64 | }) 65 | end 66 | end 67 | end 68 | end 69 | end) -------------------------------------------------------------------------------- /client/system/events.lua: -------------------------------------------------------------------------------- 1 | Events = {} 2 | ValidEvents = { 3 | ["join"] = true, 4 | ["leave"] = true, 5 | ["end"] = true, 6 | ["start"] = true, 7 | ["roundend"] = true, 8 | } 9 | 10 | -- Will check and return true/false if the event with identifier exists 11 | --- @param eventName string 12 | function ValidateEvents(eventName) 13 | return type(eventName) == "string" and ValidEvents[string.lower(eventName)] ~= nil 14 | end 15 | 16 | -- Will check and return true/false if the event with identifier exists 17 | --- @param identifier string 18 | --- @param eventName string 19 | function ValidateInvokingEvent(identifier, eventName) 20 | return Events[identifier] ~= nil and Events[identifier][eventName] 21 | end 22 | 23 | -- Will find and remove all events with the 24 | -- name of the resource 25 | --- @param nameResource string 26 | function RemoveEventsWithNameResource(nameResource) 27 | for identifier, v in pairs(Events) do 28 | for event, value in pairs(v) do 29 | for resource, val in pairs(value) do 30 | if resource == nameResource then 31 | Events[identifier][event][resource] = nil 32 | break 33 | end 34 | end 35 | end 36 | end 37 | end 38 | 39 | --Register event 40 | --Return true if event is registered, false if is not 41 | function On(identifier, eventName, cb) 42 | local invokingName = GetInvokingResource() 43 | eventName = string.lower(eventName) 44 | if not ValidateEvents(eventName) then 45 | return false 46 | end 47 | 48 | if Events[identifier] == nil then 49 | Events[identifier] = {} 50 | end 51 | 52 | if Events[identifier][eventName] == nil then 53 | Events[identifier][eventName] = {} 54 | end 55 | 56 | if Events[identifier][eventName][invokingName] == nil then 57 | Events[identifier][eventName][invokingName] = {} 58 | end 59 | table.insert(Events[identifier][eventName][invokingName], cb) 60 | return true 61 | end 62 | 63 | --Call event 64 | --- @param identifier string 65 | --- @param eventName string 66 | --- @param ... object 67 | function CallOn(identifier, eventName, ...) 68 | if ValidateInvokingEvent(identifier, eventName) then 69 | for key, value in pairs(Events[identifier][eventName]) do 70 | for k, cb in pairs(value) do 71 | if type(cb) == "table" or type(cb) == "function" then 72 | cb(...) 73 | end 74 | end 75 | end 76 | end 77 | end 78 | -------------------------------------------------------------------------------- /server/system/events.lua: -------------------------------------------------------------------------------- 1 | Events = {} 2 | ValidEvents = { 3 | ["join"] = true, 4 | ["leave"] = true, 5 | ["end"] = true, 6 | ["start"] = true, 7 | ["roundend"] = true, 8 | } 9 | 10 | -- Will check and return true/false if the event with identifier exists 11 | --- @param eventName string 12 | function ValidateEvents(eventName) 13 | return type(eventName) == "string" and ValidEvents[string.lower(eventName)] ~= nil 14 | end 15 | 16 | -- Will check and return true/false if the event with identifier exists 17 | --- @param identifier string 18 | --- @param eventName string 19 | function ValidateInvokingEvent(identifier, eventName) 20 | return Events[identifier] ~= nil and Events[identifier][eventName] 21 | end 22 | 23 | -- Will find and remove all events with the 24 | -- name of the resource 25 | --- @param nameResource string 26 | function RemoveEventsWithNameResource(nameResource) 27 | for identifier, v in pairs(Events) do 28 | for event, value in pairs(v) do 29 | for resource, val in pairs(value) do 30 | if resource == nameResource then 31 | Events[identifier][event][resource] = nil 32 | break 33 | end 34 | end 35 | end 36 | end 37 | end 38 | 39 | --Register event 40 | --Return true if event is registered, false if is not 41 | function On(identifier, eventName, cb) 42 | local invokingName = GetInvokingResource() 43 | eventName = string.lower(eventName) 44 | if not ValidateEvents(eventName) then 45 | return false 46 | end 47 | 48 | if Events[identifier] == nil then 49 | Events[identifier] = {} 50 | end 51 | 52 | if Events[identifier][eventName] == nil then 53 | Events[identifier][eventName] = {} 54 | end 55 | 56 | if Events[identifier][eventName][invokingName] == nil then 57 | Events[identifier][eventName][invokingName] = {} 58 | end 59 | table.insert(Events[identifier][eventName][invokingName], cb) 60 | return true 61 | end 62 | 63 | --Call event 64 | --- @param identifier string 65 | --- @param eventName string 66 | --- @param ... object 67 | function CallOn(identifier, eventName, ...) 68 | if ValidateInvokingEvent(identifier, eventName) then 69 | for key, value in pairs(Events[identifier][eventName]) do 70 | for k, cb in pairs(value) do 71 | if type(cb) == "table" or type(cb) == "function" then 72 | cb(...) 73 | end 74 | end 75 | end 76 | end 77 | end 78 | -------------------------------------------------------------------------------- /server/system/lobby.lua: -------------------------------------------------------------------------------- 1 | -- Checking every lobby if they're ready if so we will set each player into 2 | -- arena virtual world + calling the event "OnStart" 3 | function UpdateLobbies() 4 | SetTimeout(1000, UpdateLobbies) 5 | 6 | for k, v in pairs(ArenaList) do 7 | if IsArenaActive(k) then 8 | if v.MinimumCapacity - 1 < v.CurrentCapacity then 9 | v.MaximumLobbyTime = v.MaximumLobbyTime - 1 10 | if v.MaximumLobbyTime == 0 then 11 | v.MaximumLobbyTime = v.MaximumLobbyTimeSaved 12 | 13 | v.ArenaState = "ArenaBusy" 14 | CallOn(k, "start", v) 15 | 16 | if v.OwnWorld then 17 | for id, _ in pairs(v.PlayerList) do 18 | SetPlayerRoutingBucket(id, v.OwnWorldID) 19 | end 20 | end 21 | 22 | TriggerClientEvent("ArenaAPI:sendStatus", -1, "start", GetDefaultDataFromArena(k)) 23 | end 24 | end 25 | end 26 | if IsArenaBusy(k) then 27 | if v.CurrentCapacity == 0 then 28 | GetArenaInstance(k).Reset() 29 | end 30 | end 31 | end 32 | end 33 | 34 | SetTimeout(1000, UpdateLobbies) 35 | 36 | -- This timer will and recount times left in the arena 37 | -- if the timer run to 0 and doesnt have any rounds left it 38 | -- will call event "onEnd" if there is round it will call 39 | -- "onRoundEnd" 40 | function UpdateArenaGame() 41 | SetTimeout(1000, UpdateArenaGame) 42 | 43 | for k, v in pairs(ArenaList) do 44 | if IsArenaBusy(k) then 45 | if v.MaximumArenaTime then 46 | v.MaximumArenaTime = v.MaximumArenaTime - 1 47 | if v.MaximumArenaTime == 0 then 48 | v.MaximumArenaTime = v.MaximumArenaTimeSaved 49 | if v.CurrentRound then 50 | v.CurrentRound = v.CurrentRound - 1 51 | if v.CurrentRound == -1 then 52 | GetArenaInstance(k).Reset() 53 | TriggerClientEvent("ArenaAPI:sendStatus", -1, "end", GetDefaultDataFromArena(k)) 54 | else 55 | CallOn(k, "roundEnd", v) 56 | TriggerClientEvent("ArenaAPI:sendStatus", -1, "roundEnd", GetDefaultDataFromArena(k)) 57 | end 58 | else 59 | GetArenaInstance(k).Reset() 60 | TriggerClientEvent("ArenaAPI:sendStatus", -1, "end", GetDefaultDataFromArena(k)) 61 | end 62 | end 63 | end 64 | end 65 | end 66 | end 67 | 68 | SetTimeout(1000, UpdateArenaGame) -------------------------------------------------------------------------------- /server/main.lua: -------------------------------------------------------------------------------- 1 | ---------------------------------------- 2 | --- Variables 3 | ---------------------------------------- 4 | ArenaList = {} 5 | PlayerInfo = {} 6 | CooldownPlayers = {} 7 | WorldCount = 0 8 | ---------------------------------------- 9 | --- Functions 10 | ---------------------------------------- 11 | -- Arena creator helper, will set all default variables. 12 | --- @param identifier string 13 | --- @param identifier bool 14 | function ArenaCreatorHelper(identifier, ignore) 15 | if ArenaList[identifier] ~= nil then return ArenaList[identifier] end 16 | if not ignore then 17 | ArenaList[identifier] = { 18 | MaximumCapacity = 0, 19 | MinimumCapacity = 0, 20 | CurrentCapacity = 0, 21 | ----- 22 | MaximumRoundSaved = nil, 23 | CurrentRound = nil, 24 | ----- 25 | DeleteWorldAfterWin = true, 26 | OwnWorld = false, 27 | OwnWorldID = 0, 28 | ----- 29 | ArenaLabel = "", 30 | ArenaIdentifier = identifier, 31 | ----- 32 | MaximumArenaTime = nil, 33 | MaximumArenaTimeSaved = nil, 34 | MaximumLobbyTimeSaved = 30, 35 | MaximumLobbyTime = 30, 36 | ----- 37 | ArenaIsPublic = true, 38 | ----- 39 | PlayerList = {}, 40 | PlayerScoreList = {}, 41 | PlayerNameList = {}, 42 | ----- 43 | ArenaState = "ArenaInactive", 44 | ----- 45 | } 46 | TriggerClientEvent("ArenaAPI:sendStatus", -1, "updateData", ArenaList) 47 | end 48 | return ArenaList[identifier] 49 | end 50 | 51 | -- Will return data from "ArenaCreatorHelper" if arena does not exists 52 | -- it will return nil value 53 | --- @param identifier string 54 | function GetDefaultDataFromArena(identifier) 55 | return ArenaCreatorHelper(identifier, true) 56 | end 57 | 58 | -- Well this will just send chat message to... player :D 59 | --- @param source int 60 | --- @param string string 61 | function SendMessage(source, string) 62 | TriggerClientEvent('chat:addMessage', source, { 63 | color = { 255, 255, 255 }, 64 | multiline = true, 65 | args = { "[ArenaAPI]", string } 66 | }) 67 | end 68 | 69 | -- This is command to handle logic for joining/leaving + blocking joining arena lobby 70 | RegisterCommand("minigame", function(source, args, rawCommand) 71 | if args[1] == "join" then 72 | local arenaName = args[2] 73 | if not IsPlayerInAnyArena(source) then 74 | if DoesArenaExists(arenaName) then 75 | local arenaInfo = GetDefaultDataFromArena(arenaName) 76 | local arena = GetArenaInstance(arenaName) 77 | if arena.IsArenaPublic() then 78 | if not IsArenaBusy(arenaName) then 79 | if arenaInfo.MaximumCapacity > arenaInfo.CurrentCapacity then 80 | if not IsPlayerInCooldown(source, arenaName) then 81 | arena.MaximumLobbyTime = arena.MaximumLobbyTimeSaved 82 | GetArenaInstance(args[2]).AddPlayer(source) 83 | SendMessage(source, Config.MessageList["arena_joined"]) 84 | else 85 | SendMessage(source, string.format(Config.MessageList["cooldown_to_join"], TimestampToString(GetcooldownForPlayer(source, arenaName)))) 86 | end 87 | else 88 | SendMessage(source, Config.MessageList["maximum_people"]) 89 | end 90 | else 91 | SendMessage(source, Config.MessageList["arena_busy"]) 92 | end 93 | else 94 | SendMessage(source, Config.MessageList["cant_acces_this_arena"]) 95 | end 96 | else 97 | SendMessage(source, Config.MessageList["arena_doesnt_exists"]) 98 | end 99 | else 100 | SendMessage(source, Config.MessageList["player_in_arena"]) 101 | end 102 | end 103 | if args[1] == "leave" then 104 | if IsPlayerInAnyArena(source) then 105 | local arenaName = GetPlayerArena(source) 106 | if DoesArenaExists(arenaName) then 107 | local arena = GetArenaInstance(arenaName) 108 | CooldownPlayer(source, arenaName, Config.TimeCooldown) 109 | arena.MaximumLobbyTime = arena.MaximumLobbyTimeSaved 110 | 111 | GetArenaInstance(arenaName).RemovePlayer(source) 112 | SendMessage(source, Config.MessageList["arena_left"]) 113 | end 114 | else 115 | SendMessage(source, Config.MessageList["player_isnt_in_arena"]) 116 | end 117 | end 118 | end, false) -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | #Arena library for Fivem 2 | 3 | 4 | ### ArenaAPI functions 5 | 6 | ------------ 7 | 8 | #####Once a new arena is created, it can be acces with command: /minigame join [identifier] 9 | 10 | ------------ 11 | 12 | ###**Functions (server side)** 13 | 14 | ------------ 15 | 16 | ### About creating arena and others 17 | 18 | ------------ 19 | 20 | - CreateArena(string identifier) returns module of the arena 21 | 22 | - GetArenaInstance(string identifier) will return an instance of arena 23 | 24 | - GetArenaList() will return an array of arenas 25 | 26 | - DoesArenaExists(string identifier) true/false 27 | 28 | ------------ 29 | 30 | - IsArenaBusy(string identifier) return true / false 31 | 32 | - IsArenaActive(string identifier) return true / false 33 | 34 | - IsArenaInactive(string identifier) return true / false 35 | 36 | - GetArenaState(string identifier) return state of arena
37 | ``` 38 | ArenaInactive -- no one is in a lobby or arena 39 | ArenaActive -- people are in lobby 40 | ArenaBusy -- people playing already 41 | ``` 42 | 43 | ------------ 44 | 45 | - IsPlayerInArena(int source, string name) 46 | 47 | - IsPlayerInAnyArena(int source) 48 | 49 | - GetPlayerArena(int source) returns name of the arena, if he isnt anywhere it will return "none" 50 | 51 | ------------ 52 | 53 | ### Events 54 | 55 | ------------ 56 | 57 | - OnPlayerJoinLobby(cb)
58 | Will be called whenever someone join arena 59 | 60 | - OnPlayerExitLobby(cb)
61 | Will be called whenever player leave arena 62 | The array data returns 63 | 64 | - OnArenaStart(cb) 65 | 66 | - OnArenaEnd(cb) 67 | 68 | - OnArenaRoundEnd(cb) 69 | 70 | - On(cb)
71 | if the event is join/leave there is first argument source, second is arena instance
72 | for others such a like end,start etc, there is only one argument, and thats the arena instance. 73 | ``` 74 | { 75 | MaximumRoundSaved, 76 | CurrentRound, 77 | ArenaIdentifier, 78 | ArenaLabel, 79 | MaximumCapacity, 80 | MinimumCapacity, 81 | CurrentCapacity, 82 | } 83 | ``` 84 | 85 | Usage of these events 86 | ```LUA 87 | local arenaBuilder = exports.ArenaAPI 88 | 89 | local arena = arenaBuilder:GetArenaInstance("MyArena") 90 | 91 | arena.PlayerJoinArena(function(data) 92 | TriggerClientEvent("showNotification", data.source, "Welcome to the arena: " .. data.ArenaLabel) 93 | end) 94 | ``` 95 | 96 | Second example of events 97 | ```LUA 98 | local arenaBuilder = exports.ArenaAPI 99 | 100 | local arena = arenaBuilder:GetArenaInstance("MyArena") 101 | 102 | arena.On("join",function(source, data) 103 | TriggerClientEvent("showNotification", source, "Welcome to the arena: " .. data.ArenaLabel) 104 | end) 105 | ``` 106 | 107 | ------------ 108 | 109 | #All functions bellow are from module, so use it like this 110 | 111 | ```LUA 112 | local arenaBuilder = exports.ArenaAPI 113 | local arena = arenaBuilder:CreateArena("gungame_1") 114 | 115 | arena.SetMaximumCapacity(10) -- maximum player 116 | arena.SetMinimumCapacity(2) -- minimum to start 117 | arena.SetArenaLabel("Gungame arena #1") 118 | ``` 119 | ------------ 120 | 121 | ### Setting info about arena 122 | 123 | ------------ 124 | - SetMaximumCapacity(int number)
Will set how many people can join to the arena 125 | 126 | - SetMinimumCapacity(int number)
Will set how many players need to join to start game 127 | 128 | - SetArenaMaxRounds(int number)
How many rounds this arena will have ? 129 | 130 | - SetArenaLabel(string name) 131 | 132 | - SetOwnWorld(boolean result) when players join to the arena it will create their own world with other players 133 | 134 | - SetMaximumArenaTime(int second)
This will set for how long the arena can go, 135 | if the value isnt set the arena will be there forever 136 | 137 | - SetMaximumLobbyTime(int second)
138 | How long player have to wait in lobby before letting him into the game, 139 | if player leave the lobby the timer will reset to this value. 140 | 141 | - SetArenaPublic(boolean value)
142 | if true player will be able to acces arena from command /arena join [name] 143 | if false that means you will have to use somewhere else this function "AddPlayer(int source)" 144 | 145 | - RemoveWorldAfterWin(boolean result) if you have something like winner cutscene, set this on false, but you have to send player into world 0 by your code. 146 | 147 | ------------ 148 | 149 | ### Getting info about arena 150 | 151 | ------------ 152 | 153 | - GetMaximumCapacity() 154 | 155 | - GetMinimumCapacity() 156 | 157 | - GetMaximumRounds() 158 | 159 | - GetCurrentRound() 160 | 161 | - GetPlayerCount() 162 | 163 | - GetArenaIdentifier() 164 | 165 | - GetArenaLabel() 166 | 167 | - GetPlayerList() 168 | 169 | - GetOwnWorld() return boolean, id of world 170 | 171 | - IsArenaPublic()
true/false (means if you can acces the arena with command /minigame) 172 | 173 | ------------ 174 | 175 | **Player manipulation** 176 | 177 | ------------ 178 | 179 | - AddPlayer(int source) 180 | 181 | - RemovePlayer(int source) 182 | 183 | ------------ 184 | 185 | - Reset() 186 | 187 | - Destroy()
will destroy arena and new one has to be created 188 | 189 | ------------ 190 | 191 | - SetPlayerScore(int source, string key, object value) 192 | 193 | - GetPlayerScore(int source, string key) 194 | 195 | - GivePlayerScore(int source, string key, object value) 196 | 197 | - RemovePlayerScore(int source, string key, object value) 198 | 199 | - PlayerScoreExists(int source, string key) 200 | 201 | - DeleteScore(int source, string key) 202 | 203 | ------------ 204 | 205 | ###**Functions (client side)** 206 | 207 | ------------ 208 | 209 | - IsPlayerInAnyArena() true/false 210 | 211 | - IsPlayerInArena(string arena) 212 | 213 | - GetArenaIdentifier() 214 | 215 | - GetArenaLabel() 216 | 217 | - GetArenaMaximumSize() 218 | 219 | - GetArenaMinimumSize() 220 | 221 | - GetArenaCurrentSize() 222 | 223 | - GetCurrentArenaData() returns array 224 | - GetCurrentArenaData() returns array 225 | ``` 226 | { 227 | MaximumRoundSaved, 228 | CurrentRound, 229 | ArenaIdentifier, 230 | ArenaLabel, 231 | MaximumCapacity, 232 | MinimumCapacity, 233 | CurrentCapacity, 234 | } 235 | ``` 236 | ------------ 237 | 238 | ### Events 239 | 240 | ------------ 241 | 242 | - OnPlayerJoinLobby(string arena, cb)
243 | Will be called whenever someone join arena 244 | 245 | - OnPlayerExitLobby(string arena, cb)
246 | Will be called whenever player leave arena 247 | 248 | - OnArenaStart(string arena, cb)
249 | Will be called whenever arena started game 250 | 251 | - OnArenaEnd(string arena, cb)
252 | Will be called after arena runs out of time or player achieve enough points 253 | 254 | - OnArenaRoundEnd(string arena, cb) 255 | 256 | - On(string arena, string eventName, cb) 257 | 258 | The array data returns 259 | ``` 260 | { 261 | MaximumRoundSaved, 262 | CurrentRound, 263 | ArenaIdentifier, 264 | ArenaLabel, 265 | MaximumCapacity, 266 | MinimumCapacity, 267 | CurrentCapacity, 268 | } 269 | ``` 270 | 271 | ------------ -------------------------------------------------------------------------------- /server/module/arena.lua: -------------------------------------------------------------------------------- 1 | -- Just holder for arena virtual world ID 2 | ClaimedVirtualWorld = {} 3 | 4 | -- Will return + create Arena lobby 5 | --- @param identifier string 6 | function CreateArena(identifier) 7 | ArenaCreatorHelper(identifier) 8 | local arena = ArenaList[identifier] 9 | -------------------------------------------- 10 | local self = {} 11 | -------------------------------------------- 12 | -- Basic information about arena -- 13 | -------------------------------------------- 14 | self.SetOwnWorld = function(result) 15 | arena.OwnWorld = result 16 | if result then 17 | if ArenaList[identifier].OwnWorldID == 0 then 18 | local newID = 0 19 | for i = 1, 64 do 20 | if not ClaimedVirtualWorld[i] then 21 | newID = i 22 | ClaimedVirtualWorld[i] = i 23 | break 24 | end 25 | end 26 | if newID == 0 then 27 | print("WARNING the poolsize of virtual worlds have run out! Delete some Arena lobbies to make space!") 28 | else 29 | ArenaList[identifier].OwnWorldID = newID 30 | end 31 | end 32 | end 33 | end 34 | 35 | self.GetOwnWorld = function() 36 | return arena.OwnWorld, arena.OwnWorldID 37 | end 38 | -------- 39 | self.RemoveWorldAfterWin = function(result) 40 | arena.DeleteWorldAfterWin = result 41 | end 42 | -------- 43 | self.SetMaximumCapacity = function(number) 44 | arena.MaximumCapacity = number 45 | end 46 | 47 | self.GetMaximumCapacity = function() 48 | return arena.MaximumCapacity 49 | end 50 | -------- 51 | self.SetMinimumCapacity = function(number) 52 | arena.MinimumCapacity = number 53 | end 54 | 55 | self.GetMinimumCapacity = function() 56 | return arena.MinimumCapacity 57 | end 58 | -------- 59 | self.GetArenaIdentifier = function() 60 | return arena.ArenaIdentifier 61 | end 62 | -------- 63 | self.SetArenaLabel = function(name) 64 | arena.ArenaLabel = name 65 | end 66 | 67 | self.GetArenaLabel = function() 68 | return arena.ArenaLabel 69 | end 70 | -------- 71 | self.SetArenaMaxRounds = function(rounds) 72 | if arena.MaximumRoundSaved == nil then 73 | arena.MaximumRoundSaved = rounds 74 | end 75 | arena.CurrentRound = rounds 76 | end 77 | 78 | self.GetMaximumRounds = function() 79 | return arena.MaximumRoundSaved 80 | end 81 | 82 | self.GetCurrentRound = function() 83 | return arena.CurrentRound 84 | end 85 | -------- 86 | self.SetMaximumArenaTime = function(second) 87 | arena.MaximumArenaTime = second 88 | arena.MaximumArenaTimeSaved = second 89 | end 90 | 91 | self.GetMaximumArenaTime = function() 92 | return arena.MaximumArenaTimeSaved 93 | end 94 | -------- 95 | self.SetMaximumLobbyTime = function(second) 96 | arena.MaximumLobbyTime = second 97 | arena.MaximumLobbyTimeSaved = second 98 | end 99 | 100 | self.GetMaximumLobbyTime = function() 101 | return arena.MaximumLobbyTimeSaved 102 | end 103 | -------- 104 | self.SetArenaPublic = function(value) 105 | arena.ArenaIsPublic = value 106 | end 107 | 108 | self.IsArenaPublic = function() 109 | return arena.ArenaIsPublic 110 | end 111 | -------------------------------------------- 112 | -- Adding player into arena logic -- 113 | -------------------------------------------- 114 | self.AddPlayer = function(source) 115 | if arena.PlayerList[source] == nil then 116 | PlayerInfo[source] = arena.ArenaIdentifier 117 | arena.PlayerList[source] = true 118 | arena.PlayerScoreList[source] = {} 119 | arena.PlayerNameList[source] = GetPlayerName(source):gsub("<[^>]+>", " ") 120 | 121 | arena.CurrentCapacity = arena.CurrentCapacity + 1 122 | 123 | local data = GetDefaultDataFromArena(arena.ArenaIdentifier) 124 | 125 | CallOn(identifier, "join", source, data) 126 | 127 | arena.MaximumLobbyTime = arena.MaximumLobbyTimeSaved 128 | 129 | arena.ArenaState = "ArenaActive" 130 | 131 | TriggerClientEvent("ArenaAPI:sendStatus", -1, "updateData", ArenaList) 132 | TriggerClientEvent("ArenaAPI:sendStatus", source, "join", data) 133 | end 134 | end 135 | -------- 136 | self.RemovePlayer = function(source, skipEvent) 137 | if arena.PlayerList[source] ~= nil then 138 | if arena.DeleteWorldAfterWin then 139 | SetPlayerRoutingBucket(source, 0) 140 | end 141 | 142 | PlayerInfo[source] = "none" 143 | arena.PlayerList[source] = nil 144 | arena.PlayerScoreList[source] = nil 145 | arena.PlayerNameList[source] = nil 146 | 147 | arena.CurrentCapacity = arena.CurrentCapacity - 1 148 | if arena.CurrentCapacity == 0 then 149 | arena.ArenaState = "ArenaInactive" 150 | end 151 | 152 | local data = GetDefaultDataFromArena(arena.ArenaIdentifier) 153 | 154 | CallOn(identifier, "leave", source, data) 155 | 156 | arena.MaximumLobbyTime = arena.MaximumLobbyTimeSaved 157 | 158 | TriggerClientEvent("ArenaAPI:sendStatus", -1, "updateData", ArenaList) 159 | if skipEvent == nil then TriggerClientEvent("ArenaAPI:sendStatus", source, "leave", data) end 160 | end 161 | end 162 | -------- 163 | self.GetPlayerList = function() 164 | return arena.PlayerList 165 | end 166 | -------- 167 | self.IsPlayerInArena = function(source) 168 | return arena.PlayerList[source] ~= nil 169 | end 170 | -------------------------------------------- 171 | -- Setting player score logic -- 172 | -------------------------------------------- 173 | self.SetPlayerScore = function(source, key, value) 174 | arena.PlayerScoreList[source][key] = value 175 | end 176 | -------- 177 | self.GetPlayerScore = function(source, key) 178 | return arena.PlayerScoreList[source][key] 179 | end 180 | -------- 181 | self.GivePlayerScore = function(source, key, value) 182 | arena.PlayerScoreList[source][key] = arena.PlayerScoreList[source][key] + value 183 | end 184 | -------- 185 | self.RemovePlayerScore = function(source, key, value) 186 | arena.PlayerScoreList[source][key] = arena.PlayerScoreList[source][key] - value 187 | end 188 | -------- 189 | self.PlayerScoreExists = function(source, key) 190 | return arena.PlayerScoreList[source][key] ~= nil 191 | end 192 | -------- 193 | self.DeleteScore = function(source, key) 194 | arena.PlayerScoreList[source][key] = nil 195 | end 196 | -------------------------------------------- 197 | -- Basic manipulation arena -- 198 | -------------------------------------------- 199 | self.Destroy = function() 200 | CallOn(identifier, "end", arena) 201 | 202 | for k, v in pairs(arena.PlayerList) do 203 | self.RemovePlayer(k) 204 | end 205 | 206 | ClaimedVirtualWorld[ArenaList[identifier].OwnWorldID] = nil 207 | TriggerClientEvent("ArenaAPI:sendStatus", -1, "end", GetDefaultDataFromArena(arena.ArenaIdentifier)) 208 | ArenaList[identifier] = nil 209 | end 210 | -------- 211 | self.Reset = function() 212 | CallOn(identifier, "end", arena) 213 | 214 | for k, v in pairs(arena.PlayerList) do 215 | self.RemovePlayer(k, true) 216 | end 217 | 218 | ClaimedVirtualWorld[ArenaList[identifier].OwnWorldID] = nil 219 | 220 | arena.PlayerList = {} 221 | arena.PlayerScoreList = {} 222 | arena.ArenaState = "ArenaInactive" 223 | 224 | arena.MaximumArenaTime = arena.MaximumArenaTimeSaved 225 | arena.CurrentRound = arena.MaximumRoundSaved 226 | end 227 | -------------------------------------------- 228 | -- Basic events for arena -- 229 | -------------------------------------------- 230 | self.OnPlayerJoinLobby = function(cb, test) 231 | return On(identifier, "join", cb) 232 | end 233 | 234 | self.OnPlayerExitLobby = function(cb) 235 | return On(identifier, "leave", cb) 236 | end 237 | 238 | self.OnArenaStart = function(cb) 239 | return On(identifier, "start", cb) 240 | end 241 | 242 | self.OnArenaEnd = function(cb) 243 | return On(identifier, "end", cb) 244 | end 245 | 246 | self.OnArenaRoundEnd = function(cb) 247 | return On(identifier, "roundEnd", cb) 248 | end 249 | 250 | self.On = function(eventName, cb) 251 | return On(identifier, eventName, cb) 252 | end 253 | -------------------------------------------- 254 | return self 255 | end 256 | 257 | exports("CreateArena", CreateArena) 258 | 259 | function GetArenaInstance(identifier) 260 | return CreateArena(identifier) 261 | end 262 | 263 | exports("GetArenaInstance", GetArenaInstance) --------------------------------------------------------------------------------