Looking for improvements on large core game script

Hello! So I have this very veryyyy large script with 2k lines of code (Down below is a 3rd of the entire script because of max characters). The issue I am facing is I really want to make this code more modular, maybe with some modulescripts. But the issue is although I know how to use modulescripts, I don’t know how to make it work with passing playerData. How should I go with doing this?



-- Set CharacterAutoLoads to false
game.Players.CharacterAutoLoads = false
game.StarterPlayer.EnableMouseLockOption = false
game.StarterPlayer.CameraMode = Enum.CameraMode.LockFirstPerson

local playerFaction = {}

-- This will be used to store player data
local playerData = {}
local playerStats = {}
local playerPos = {}

-- This posts to an external api which moderates webhook amount

local battlelogWebhook = "Removed for security"
local failureWebhook = "Removed for security"
local successWebhook = "Removed for security"

-- Increase this value by 1 to wipe data
local dataStoreVersion = 102

local debugMode = false

---------------------------------------------------------------

-- Players
local Players = game:GetService("Players")

-- Http Service
local HttpService = game:GetService("HttpService")

-- Run Service
local RunService = game:GetService("RunService")

-- Inventory Folder and remotes
local replicatedStorage = game:GetService("ReplicatedStorage") 

-- Inventory
local inventories = script:WaitForChild("Inventories")
local inventoryRemotes = replicatedStorage:WaitForChild("InventoryRemotes")

-- This is for item dropping
local itemPlacement = require(script.Parent:WaitForChild("WorldLoad"):WaitForChild("PlaceItem"))
local reqDrop = inventoryRemotes:WaitForChild("DropItem")

-- Request Table Invoke
local requestTable = inventoryRemotes:WaitForChild("RequestTable")

-- Request 
local requestInventoryUpdate = inventoryRemotes:WaitForChild("RequestTableUpdate")

-- Give player specific item
local givePlrItem = replicatedStorage:WaitForChild("AdministrativeRemotes"):WaitForChild("GiveItem")
local requestClear = replicatedStorage:WaitForChild("AdministrativeRemotes"):WaitForChild("ClearInv")
local setHealth = replicatedStorage:WaitForChild("AdministrativeRemotes"):WaitForChild("SetHealth")
local KillPlayer = replicatedStorage:WaitForChild("AdministrativeRemotes"):WaitForChild("KillPlayer")
local serverRequests = script.Parent:WaitForChild("ServerRequests")
local massMessage = serverRequests:WaitForChild("MassMessage")
local messagePlayer = serverRequests:WaitForChild("MessagePlayer")

-- Saving stats
local requestSave = inventoryRemotes:WaitForChild("SaveStats")

-- Swapping Items
local requestSwap = inventoryRemotes:WaitForChild("SwapItem")

-- This is for picking up items
local reqPickUp = inventoryRemotes:WaitForChild("PickUp")

-- This is for changing settings
local reqPickUp = inventoryRemotes:WaitForChild("PickUp")

-- This is for engine remotes
local engineRemotes = replicatedStorage:WaitForChild("EngineRemotes")

local healthUpdate = inventoryRemotes:WaitForChild("HealthChanged")

local changeSettings = inventoryRemotes:WaitForChild("ChangeSettings")
local changeStats = inventoryRemotes:WaitForChild("RequestStatsUpdate")

local requestLeave = inventoryRemotes:WaitForChild("RequestLeave")
local pickupAnimation = replicatedStorage:WaitForChild("ManipulationRemotes"):WaitForChild("PickupAnim")
local fullSound = replicatedStorage:WaitForChild("ManipulationRemotes"):WaitForChild("FullSound")
local setDebug = replicatedStorage:WaitForChild("ManipulationRemotes"):WaitForChild("RequestDebug")
local RequestEquip = replicatedStorage:WaitForChild("EngineRemotes"):WaitForChild("EquipItem")
local forceEquip = replicatedStorage:WaitForChild("EngineRemotes"):WaitForChild("ForceEquip")
local changeHealthEvent = serverRequests:WaitForChild("ChangeHealth")
local requestReload = replicatedStorage:WaitForChild("EngineRemotes"):WaitForChild("RequestReload")
local equipUpdate = replicatedStorage:WaitForChild("EngineRemotes"):WaitForChild("EquipUpdate")
local consumeAnim = replicatedStorage:WaitForChild("EngineRemotes"):WaitForChild("ConsumeAnimation")
local refreshSlot = inventoryRemotes:WaitForChild("RefreshSlot")
local updateFood = inventoryRemotes:WaitForChild("UpdateFood")
local playFill = inventoryRemotes:WaitForChild("PlayFillNoise")
local fireEvent = replicatedStorage:WaitForChild("EngineRemotes"):WaitForChild("FireEvent")
local createBullet = script.Parent:WaitForChild("ServerRequests"):WaitForChild("CreateBullet")
local runFire = replicatedStorage:WaitForChild("EngineRemotes"):WaitForChild("RunFireAnim")
local runReload = replicatedStorage:WaitForChild("EngineRemotes"):WaitForChild("RunReloadAnim")
local damagePlr = serverRequests:WaitForChild("DamagePlyr")
local firetheData = script:WaitForChild("FireTheSpill")
local requestingSpawn = engineRemotes:WaitForChild("RequestSpawn")
local podSpawn = serverRequests:WaitForChild("RequestPodSpawning")
local recieveTeam = replicatedStorage:WaitForChild("ManipulationRemotes"):WaitForChild("RecieveTeam")
local changeTeamRemote = replicatedStorage:WaitForChild("ManipulationRemotes"):WaitForChild("ChangeTeam")
local addBackpack = serverRequests:WaitForChild("AddBackpack")
local removeBackpack = serverRequests:WaitForChild("RemoveBackpack")
local fireDeathAnim = script:WaitForChild("FireDeathAnimation")
local setArmState = serverRequests:WaitForChild("SetArmState")
local posUpdate = serverRequests:WaitForChild("PositionUpdate")

local getFacCount = serverRequests:WaitForChild("GetFactionCount")
local closeFacMenu = inventoryRemotes:WaitForChild("CloseFactionMenu")

local defaultModule = require(script:WaitForChild("DefaultData"))

-- This would just encode the default json
local defaultJson = HttpService:JSONEncode(defaultModule.GetDefaultTable()) -- Converts table into a json format
local defaultStatsJson = HttpService:JSONEncode(defaultModule.GetDefaultStats())

local function postLog(name, reason, version, json, webhook, player, isSuccess)
	
	if debugMode or isSuccess ~= 1 then

		local color = tonumber(0xffff66)
		if isSuccess == 1 then
			color = tonumber(0x00ff00)
		elseif isSuccess == 3 then
			color = tonumber(0xff0000)
		elseif isSuccess == 2 then
			color = tonumber(0xcc66ff)
		end
	
		local success, message = pcall(function()
			local http = game:GetService("HttpService")
			local Data = 
			{
				["content"] = "",
				["embeds"] = {{
					["title"] = "__**" .. name .. "**__",
					["description"] = version,
					["type"] = "rich",
					["color"] = color,
					["fields"] = {
						{
							["name"] = "__" .. reason .. "__",
							["value"] = json,
							["inline"] = true
						}--[[,
						{
							["name"] = "__Title__",
							["value"] = "hi",
							["inline"] = true
						}]]
					}
				}}
			}
			Data = HttpService:JSONEncode(Data)
			HttpService:PostAsync(webhook, Data)
		end)

	end
end

local function exchangeBackPack(Player, backPackTable)
	if backPackTable ~= nil and backPackTable ~= "None" and backPackTable["Name"] ~= nil then
		removeBackpack:Fire(Player)
		local findBackpack = itemPlacement.returnObjectWithName(backPackTable["Name"])
		if findBackpack ~= nil then
			addBackpack:Fire(Player, findBackpack)
		end
	end
end

-- This will return the maximum number of slots a player has based upon their equipped
local function getMaxSlots(Player)
	local bag = playerData[Player.Name]["bagEquipped"]
	if bag ~= nil then
		local numSlots = bag["Slots"]
		if numSlots ~= nil then
			return numSlots
		end
	end
	return 8
end

local function DebugMode(player)
	if player:GetRankInGroup(4975640) >= 50 then
		if debugMode then
			debugMode = false
			massMessage:Fire("The " .. player:GetRoleInGroup(4975640):lower() .. " " .. player.Name .. " has disabled debug mode for this server.")
		else
			debugMode = true
			massMessage:Fire("The " .. player:GetRoleInGroup(4975640):lower() .. " " .. player.Name .. " has enabled debug mode for this server.")	
		end
	else
		messagePlayer:Fire(player, "Your group rank of " .. player:GetRoleInGroup(4975640):lower() .. " does not give you permission.")
	end
end

-- This is utilized to set states to false if the player were to rejoin
local function setAllStatesToFalse(player)
	local getplayerInventory = inventories:FindFirstChild(player.Name)
	if getplayerInventory ~= nil then
		local children = getplayerInventory:GetChildren()
		for i, child in ipairs(children) do
			if child:IsA("BoolValue") then
				child.Value = false
			end
		end
	end
end


-- This is used to create an inventory within the server
local function createInventory(player)
	if inventories:FindFirstChild("player.Name") == nil then
		--Create Inventory
		local playerInventory = Instance.new("StringValue", inventories)
		playerInventory.Name = player.Name
		
		--BattleLog
		local battleBool = Instance.new("BoolValue", playerInventory)
		battleBool.Name = "InBattle"
		
		--SpawnValue
		local spawnedBool = Instance.new("BoolValue", playerInventory)
		spawnedBool.Name = "Spawned"
		
		--IsRunning
		local spawnedBool = Instance.new("BoolValue", playerInventory)
		spawnedBool.Name = "Running"
		
		---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- REMOVE THIS IN THE FUTURE
		spawnedBool.Value = true
		----------------------------------------------------------------------------------------
		
		--Stats
		local faction = Instance.new("StringValue", playerInventory)
		faction.Name = "Faction"
		
		if playerFaction[player.Name] == nil then
			faction.Value = "None"
			playerFaction[player.Name] = "None"
		else
			faction.Value = playerFaction[player.Name]
		end
		
		if debugMode then
			print("Information Loaded")
		end
	else
		setAllStatesToFalse(player)
	end
end

-- Detect if a player has spawned via their name
local function isPlayerNameSpawned(playerName)
	local playerVariable = inventories:FindFirstChild(playerName)
	if playerVariable ~= nil then
		local playerSpawned = playerVariable:FindFirstChild("Spawned")
		if playerSpawned ~= nil and playerSpawned.Value == true then
			return true
		end
	end
	return false
end
-- Detects if a player has spawned based upon their character
local function isPlayerSpawned(player)
	return isPlayerNameSpawned(player.Name)
end

-- This updates the player's position for security reasons
local function updatePos(player, torsoPos)
	if isPlayerSpawned(player) then
		playerPos[player.Name] = torsoPos
	else
		playerPos[player.Name] = nil
	end
end


-- This allows the user to change the state
local function setSpawnState(player, state)
	local success, response = pcall(function()
		local playerVariable = inventories:FindFirstChild(player.Name)
		if playerVariable ~= nil then
			local playerSpawned = playerVariable:FindFirstChild("Spawned")
			if playerSpawned ~= nil then
				playerSpawned.Value = state
			end
		end
	end)
	if success then return true end
	return false	
end

-- Retrieves the table for use
function retrieveTable(player)
	--print(playerData[player.Name])
	return playerData[player.Name]
	--Deprecated version for the table
	--return inventories[player.Name].Value
end

-- Gets magnitude between the player
local function getMagnitude(part, player)
	--[[local char = player.Character
	
	if char ~= nil and part ~= nil then
		local head = char:FindFirstChild("Head")
		if head ~= nil then
			local partLocation = part.Position
			local headPos = head.Position
			return (partLocation - headPos).Magnitude
			
		else return nil
		end
	else return nil
	end]]
	if playerPos[player.Name] ~= nil and part ~= nil then
		return (playerPos[player.Name] - part.Position).Magnitude
	end
	return nil
end

local rng1 = Random.new(os.time())
local rand = rng1:NextInteger(0,1000)

-- This adds a slot item into the inventory (ITEM MUST EXIST IN WORKSPACE THOUGH)
local function addSlotItem(player, slot, object, numero)
	
	-- This just exists to help the game
	--inventories[player.Name].Faction.Value = playerStats[player.Name]["team"]
	
	for i = 1, 64 do
		local leSlot = "Slot" .. i
		if playerData[player.Name][leSlot] == nil then
			playerData[player.Name][leSlot] = {}
			messagePlayer:Fire(player, "Empty slot in database glitched (Likely caused by high ping), fixed " .. leSlot .. ".")
		end
	end
	
	if object.Type ~= nil and object.PrimaryPart ~= nil then -- This ensures reliability
		
		if (numero ~= nil and numero == rand) or (getMagnitude(object.PrimaryPart, player) ~= nil and getMagnitude(object.PrimaryPart, player) < 11) then -- If player is within the vicinity of the item (This is for security purposes)
		
			if object.Type.Value == "Gun" then
			
				print("ReachedGun")
				
				local slotName = "Slot" .. slot
	
				playerData[player.Name][slotName]["Name"] = object.Name
				playerData[player.Name][slotName]["Barrel"] = object.Barrel.Value
				playerData[player.Name][slotName]["Chambered"] = object.Chambered.Value
				playerData[player.Name][slotName]["Frequency"] = object.Frequency.Value
				playerData[player.Name][slotName]["GunType"] = object.GunType.Value
				playerData[player.Name][slotName]["Magazine"] = object.Magazine.Value
				playerData[player.Name][slotName]["RPS"] = object.RPS.Value
				playerData[player.Name][slotName]["SideBarrel"] = object.SideBarrel.Value
				playerData[player.Name][slotName]["Sight"] = object.Sight.Value
				playerData[player.Name][slotName]["Type"] = object.Type.Value
				playerData[player.Name][slotName]["UnderBarrel"] = object.UnderBarrel.Value
				playerData[player.Name][slotName]["BulletType"] = object.BulletType.Value
				playerData[player.Name][slotName]["Recoil"] = object.Recoil.Value
				playerData[player.Name][slotName]["MaxDamage"] = object.MaxDamage.Value
				playerData[player.Name][slotName]["MinDamage"] = object.MinDamage.Value
				playerData[player.Name][slotName]["BulletVelocity"] = object.BulletVelocity.Value
				playerData[player.Name][slotName]["ReloadTime"] = object.ReloadTime.Value
				playerData[player.Name][slotName]["AimTime"] = object.AimTime.Value
				playerData[player.Name][slotName]["AimFOV"] = object.AimFOV.Value
				
				
				if object.Magazine.Value ~= "None" then
					local mag = object:FindFirstChild(object.Magazine.Value)
					
					if mag ~= nil then
						playerData[player.Name][slotName]["MagLeft"] = mag.Left.Value
						playerData[player.Name][slotName]["MagMax"] = mag.Max.Value
					else
						playerData[player.Name][slotName]["Magazine"] = "None"
						playerData[player.Name][slotName]["MagLeft"] = "NA"
						playerData[player.Name][slotName]["MagMax"] = "NA"
					end
				else
					playerData[player.Name][slotName]["Magazine"] = "None"
					playerData[player.Name][slotName]["MagLeft"] = "NA"
					playerData[player.Name][slotName]["MagMax"] = "NA"
				end
				
				--playerData[player.Name][slot]
				
				
				print(object.Name .. " picked up successfully to slot " .. slot)
				
				local selectedTablePLSWork =  playerData[player.Name][slotName]
				
				--local  encodedJson = HttpService:JSONEncode(selectedTablePLSWork)
				--print(selectedTablePLSWork["Name"])--selectedTablePLSWork["Name"])
				object:Destroy()
				
			elseif object.Type.Value == "Mag" then
				if debugMode then
					print("ReachedMag")
				end
				
				local slotName = "Slot" .. slot
	
				playerData[player.Name][slotName]["Name"] = object.Name
				playerData[player.Name][slotName]["Type"] = object.Type.Value
				playerData[player.Name][slotName]["BulletType"] = object.BulletType.Value
				playerData[player.Name][slotName]["Left"] = object.Left.Value
				playerData[player.Name][slotName]["Max"] = object.Max.Value
				
				--playerData[player.Name][slot]
				
				if debugMode then
					print(object.Name .. " picked up successfully to slot " .. slot)
				end
				
				local selectedTablePLSWork =  playerData[player.Name][slotName]
				
				--local  encodedJson = HttpService:JSONEncode(selectedTablePLSWork)
				--print(selectedTablePLSWork["Name"])--selectedTablePLSWork["Name"])
				object:Destroy()
				
			elseif object.Type.Value == "Food" or object.Type.Value == "Medical" or object.Type.Value == "Drink" then
				local slotName = "Slot" .. slot
				
				playerData[player.Name][slotName]["Name"] = object.Name
				playerData[player.Name][slotName]["Type"] = object.Type.Value
				playerData[player.Name][slotName]["RestorationAmount"] = object.RestorationAmount.Value
				
				--playerData[player.Name][slot]
				
				if debugMode then
					print(object.Name .. " picked up successfully to slot " .. slot)
				end
				
				local selectedTablePLSWork =  playerData[player.Name][slotName]
				
				--local  encodedJson = HttpService:JSONEncode(selectedTablePLSWork)
				--print(selectedTablePLSWork["Name"])--selectedTablePLSWork["Name"])
				object:Destroy()
			elseif object.Type.Value == "Backpack" then
				local slotName = "Slot" .. slot
				
				playerData[player.Name][slotName]["Name"] = object.Name
				playerData[player.Name][slotName]["Type"] = object.Type.Value
				playerData[player.Name][slotName]["Slots"] = object.Slots.Value
				
				--playerData[player.Name][slot]
				
				if debugMode then
					print(object.Name .. " picked up successfully to slot " .. slot)
				end
				
				local selectedTablePLSWork =  playerData[player.Name][slotName]
				
				--local  encodedJson = HttpService:JSONEncode(selectedTablePLSWork)
				--print(selectedTablePLSWork["Name"])--selectedTablePLSWork["Name"])
				object:Destroy()			
			end
			
		end
		
	end
	
end

-- This clears a slot
local function clearSlot(player, slot)
	if player ~= nil and slot ~= nil then
		playerData[player.Name][slot] = {}
	else
		messagePlayer:Fire(player, "Something went wrong when clearing a slot")
	end
end

-- If the player is new, then set default
local function setDefault(player, reason)
	
	--local plrData = {}
	--plrData = playerData[player.Name]
	
	local success, errorMessage = pcall(function()
		playerData[player.Name] = defaultModule.GetDefaultTable()
	end)
	
	if success then
		if debugMode then
			print("Default inventory Loaded")
		end
		healthUpdate:FireClient(player, playerData[player.Name]["Health"])
	else
		setDefault(player, reason)
	end
end

local function weldItem(obj0, obj1, CF0)
	
	obj1.CFrame = obj0.CFrame
	
    local weld = Instance.new("Weld", obj1)
    weld.Part0 = obj1 --Attach to Part1
    weld.Part1 = obj0 --Attack to Part0
  	weld.C0 = CF0 * CFrame.new(0,obj0.Size.Y/2,0)--CFrame.new(0, 0, 0) + Vector3.new(0,obj0.Size.Y/2,0)
end

local function deleteChildren(Parent)
	local children = Parent:GetChildren()
	for i = 1, #children do
		local child = children[i]
		child:Destroy()
	end
end

local function weldAll(Object)
	local parts = {}
	local last
	local function scan(parent)
		for _,v in pairs(parent:GetChildren()) do
			if (v:IsA("BasePart")) then
				if (last) then
					local w = Instance.new("Weld")
					w.Name = ("%s_Weld"):format(v.Name)
					w.Part0,w.Part1 = last,v
					w.C0 = last.CFrame:inverse()
					w.C1 = v.CFrame:inverse()
					w.Parent = last
				end
				last = v
				table.insert(parts,v)
			end
			scan(v)
		end
	end
	scan(Object)
	for _,v in pairs(parts) do
		v.Anchored = false
	end
end

local function prepareObject(Object)
	local descendants = Object:GetDescendants()
	for index, descendant in pairs(descendants) do
		if Object:IsA("BasePart") or Object:IsA("MeshPart") then
			Object.Anchored = true
		elseif Object:IsA("Weld") then
			Object:Destroy()
		end
	end
	weldAll(Object)
end

local function visualizeEquip(Player, itemType, slot)
	local character = Player.Character
	
	if character ~= nil then
		character:WaitForChild("ItemType").Value = itemType
		local folderToManipulate = character:FindFirstChild("EquippedVisualized") -- This folder is used to hold externally visualed items that are equipped
		
		if folderToManipulate ~= nil then
			
			deleteChildren(folderToManipulate)
				
			if playerData[Player.Name][slot] ~= nil then
				
				local foundObject = itemPlacement.findItemFromName(playerData[Player.Name][slot]["Name"])
				
				if itemType ~= nil then
					local ClonedObject = foundObject:Clone()
					prepareObject(ClonedObject)
					ClonedObject.Parent = folderToManipulate
					local rightArm = character:FindFirstChild("Right Arm")
					local leftArm = character:FindFirstChild("Left Arm")
					
					if itemType == "Gun" and rightArm ~= nil then
						ClonedObject.PrimaryPart = ClonedObject:WaitForChild("RightHandNode")
						local primPart = ClonedObject.PrimaryPart
						weldItem(rightArm, primPart, CFrame.new(-0.3,0,0) * CFrame.Angles(math.rad(270),math.rad(180),math.rad(90)))		
					elseif itemType == "Item" and leftArm ~= nil then
						local primPart = ClonedObject.PrimaryPart
						weldItem(leftArm, primPart, CFrame.new(0,-0.5,0) * CFrame.Angles(math.rad(270),math.rad(180),math.rad(0)))
					end
				end
			end	
		end
	end
end


local function ArmStateSet(Player, slot)
	if slot == "None" or slot == nil then
		setArmState:Fire(Player, "Default")		
		visualizeEquip(Player, "Default", slot)
	elseif playerData[Player.Name][slot]["Type"] == "Gun" then
		setArmState:Fire(Player, "Gun")
		visualizeEquip(Player, "Gun", slot)
	else
		setArmState:Fire(Player, "Item")
		visualizeEquip(Player, "Item", slot)
	end
end


-- If the player has saved data, then apply the table
local function applyTable (player, Json)

	playerData[player.Name] = HttpService:JSONDecode(Json)
	postLog(player.Name, "Inventory successfully loaded", "(DS Version " .. dataStoreVersion .. ")", Json, successWebhook, player, 1)
	--changeHealthEvent:Fire(player, playerData[player.Name]["Health"])
	if playerData[player.Name] ~= nil and playerData[player.Name]["Health"] ~= nil and tonumber(playerData[player.Name]["Health"]) <= 0 then setDefault(player, "Died") end
	healthUpdate:FireClient(player, playerData[player.Name]["Health"])

	-- This would tell the player to equip
	playerData[player.Name]["equipped"] = "None"
	--[[if playerData[player.Name]["equipped"] ~= "None" then
		local slotNum = playerData[player.Name]["equipped"]
		ArmStateSet(player, slotNum)
		forceEquip:FireClient(player, slotNum, playerData[player.Name][slotNum])
	end]]
	updateFood:FireClient(player, playerData[player.Name]["food"], playerData[player.Name]["water"])
		--Deprecated way for the table
		--inventories[player.Name].Stats.Value = Json
				
end

-- If the player has saved stats
local function applyStats (player, Json)
	playerStats[player.Name] = HttpService:JSONDecode(Json)
	postLog(player.Name, "Stats successfully loaded", "(DS Version " .. dataStoreVersion .. ")", Json, successWebhook, player, 1)
	--inventories[player.Name].Faction.Value = playerStats[player.Name]["team"]
	requestInventoryUpdate:FireClient(player, retrieveTable(player), getMaxSlots(player))
end


-- If the player is new, then set default stats
local function setDefaultStats(player, reason)
	local plrData = {}
	local success, errorMessage = pcall(function()
		playerStats[player.Name] = defaultModule.GetDefaultStats()
	end)
	
	if success then
		if debugMode then
			print("Saved Stats Loaded")
		end
		postLog(player.Name, "Stats set to default", "(DS Version " .. dataStoreVersion .. ")", "None", successWebhook, player, 2)
		--inventories[player.Name].Faction.Value = "None"
	else
		wait(0.2)
		setDefaultStats(player, reason)
		postLog(player.Name, "Stats failed to set to default", "(DS Version " .. dataStoreVersion .. ")", "None", failureWebhook, player, 3)
	end
	
end

function retrieveTableJson(player)
	local encodedJson = HttpService:JSONEncode(retrieveTable(player))
	--print(encodedJson)
	return encodedJson
end

-- Retrieves the table for use
function retrieveStats(player)
	
	return playerStats[player.Name]
	--Deprecated version for the table
	--return inventories[player.Name].Stats.Value
end

function retrieveStatsJson(player)
	
	local encodedJson = HttpService:JSONEncode(playerStats[player.Name])
	--print(encodedJson)
	
	return encodedJson
end

-- Destroys the table
function destroyTable(player)
	return inventories[player.Name]:Destroy()
end

-- Gets log information
function hasLogged(player)
	return inventories[player.Name].InBattle.Value
end

-- DataStore Inventory
local dataStoreService = game:GetService("DataStoreService")
local myDataStore = dataStoreService:GetDataStore("Inventory")

local function wipeData(player, reason)
	--[[myDataStore:SetAsync(player.UserId.."-Inventory"..dataStoreVersion, defaultJson) -- Saves the inventory
	wait(1)
	local data = myDataStore:GetAsync(player.UserId.."-Inventory"..dataStoreVersion)
	wait(1)
	-- Check to ensure that data doesnt equal nil
	if data == nil or data == false then
		print("Saving did not load for " .. player.Name .. ". Trying Again...")
		wipeData(player, reason)
		postLog(player.Name, "Inventory failed to wipe, trying again...", "(DS Version " .. dataStoreVersion .. ")", "None", failureWebhook, player, 3)
		
	end
		postLog(player.Name, "Inventory successfully wiped for " .. reason, "(DS Version " .. dataStoreVersion .. ")", "None", battlelogWebhook, player, 2)
	messagePlayer:Fire(player, "Your inventory was wiped for" .. reason)]]
	local success, err = pcall(function()
		myDataStore:SetAsync(player.UserId.."-Inventory"..dataStoreVersion, defaultJson) -- Saves the inventory
	end)
	
	if success then
		postLog(player.Name, "Inventory successfully wiped for " .. reason, "(DS Version " .. dataStoreVersion .. ")", "None", battlelogWebhook, player, 2)
		if game.Players[player.Name] ~= nil then
			messagePlayer:Fire(player, "Your inventory was wiped for" .. reason)		
			playerData[player.Name] = defaultModule.GetDefaultTable()
			requestInventoryUpdate:FireClient(player, retrieveTable(player), getMaxSlots(player))
		end		
	else
		print("Saving did not load for " .. player.Name .. ". Trying Again...")
		postLog(player.Name, "Inventory failed to wipe, trying again...", "(DS Version " .. dataStoreVersion .. ")", "None", failureWebhook, player, 3)	
		wipeData(player, reason)	
	end
end

--This will save and verify that the information is saved. If the information is not saved then continue to try again until it is able to
function saveAndVerifyInventory(player)
	
	--[[--Save Information
	myDataStore:SetAsync(player.UserId.."-Inventory"..dataStoreVersion, retrieveTableJson(player)) -- Saves the inventory
	wait(0.5)
	--This would double check that the information does not equal false or nil
	local data = myDataStore:GetAsync(player.UserId.."-Inventory"..dataStoreVersion)
	wait(0.5)
	if data == nil or data == false then
		print("Saving did not load for " .. player.Name .. ". Trying Again...")
		postLog(player.Name, "Inventory failed to save. Trying again...", "(DS Version " .. dataStoreVersion .. ")", retrieveTableJson(player), failureWebhook, player, 3)
		saveAndVerifyInventory(player)
	end
		postLog(player.Name, "Inventory successfully saved!", "(DS Version " .. dataStoreVersion .. ")", retrieveTableJson(player), successWebhook, player, 1)]]
	local success, err = pcall(function()
		myDataStore:SetAsync(player.UserId.."-Inventory"..dataStoreVersion, retrieveTableJson(player)) -- Saves the inventory
	end)
	
	if success then
		postLog(player.Name, "Inventory successfully saved!", "(DS Version " .. dataStoreVersion .. ")", retrieveTableJson(player), successWebhook, player, 1)
	else
		print("Saving did not load for " .. player.Name .. ". Trying Again...")
		postLog(player.Name, "Inventory failed to save. Trying again...", "(DS Version " .. dataStoreVersion .. ")", retrieveTableJson(player), failureWebhook, player, 3)
		saveAndVerifyInventory(player)	
	end
end

--This will save and verify that the information is saved. If the information is not saved then continue to try again until it is able to
function saveAndVerifyStats(player)
	playerFaction[player.Name] = inventories:WaitForChild(player.Name).Faction.Value
	--[[--Save Information
	myDataStore:SetAsync(player.UserId.."-Stats"..dataStoreVersion, retrieveStatsJson(player)) -- Saves the inventory
	wait(0.5)
	--This would double check that the information does not equal false or nil
	local data = myDataStore:GetAsync(player.UserId.."-Stats"..dataStoreVersion)
	wait(0.5)
	if data == nil or data == false then
		print("Saving did not load for " .. player.Name .. ". Trying Again...")
		postLog(player.Name, "Stats failed to save. Trying again...", "(DS Version " .. dataStoreVersion .. ")", retrieveStatsJson(player), failureWebhook, player, 3)
		saveAndVerifyStats(player)
	end
		postLog(player.Name, "Stats successfully saved!", "(DS Version " .. dataStoreVersion .. ")", retrieveStatsJson(player), successWebhook, player, 1)]]
	local success, err = pcall(function()
		myDataStore:SetAsync(player.UserId.."-Stats"..dataStoreVersion, retrieveStatsJson(player)) -- Saves the inventory		
	end)		
	
	if success then
		postLog(player.Name, "Stats successfully saved!", "(DS Version " .. dataStoreVersion .. ")", retrieveStatsJson(player), successWebhook, player, 1)
	else
		print("Saving did not load for " .. player.Name .. ". Trying Again...")
		postLog(player.Name, "Stats failed to save. Trying again...", "(DS Version " .. dataStoreVersion .. ")", retrieveStatsJson(player), failureWebhook, player, 3)		
		saveAndVerifyStats(player)
	end
end

local function fillMag(Player, slot1, slot2)
	local max1 = playerData[Player.Name][slot1]["Max"]
	local max2 = playerData[Player.Name][slot2]["Max"]
	local left1 = playerData[Player.Name][slot1]["Left"]
	local left2 = playerData[Player.Name][slot2]["Left"]
	
	local newLeft1 = left1
	local newLeft2 = left2
	
	while newLeft1 > 0 and newLeft2 < max2 do
		newLeft1 = newLeft1 - 1
		newLeft2 = newLeft2 + 1
	end
	
	
	playerData[Player.Name][slot1]["Left"] = newLeft1
	playerData[Player.Name][slot2]["Left"] = newLeft2
	
end

local function swapItems(player, slot1, slot2)

	if slot1 ~= nil and slot2 ~= nil and player~= nil then -- If nothing is nil, then lets swap the slots
		
		-- Change position of equipped
		if playerData[player.Name]["equipped"] == slot1 then
			playerData[player.Name]["equipped"] = slot2
			--forceEquip:FireClient(player, slot2, playerData[player.Name][slot2])
		elseif playerData[player.Name]["equipped"] == slot2 then
			playerData[player.Name]["equipped"] = slot1
			--forceEquip:FireClient(player, slot1, playerData[player.Name][slot1])
		end
		
		-- Swap the slots
		local storedSlot1 = playerData[player.Name][slot1]
		playerData[player.Name][slot1] = playerData[player.Name][slot2]
		playerData[player.Name][slot2] = storedSlot1
		
		-- This is for magazine bullet filling
		if playerData[player.Name][slot1]["Type"] == "Mag" and playerData[player.Name][slot2]["Type"] == "Mag" then
			local type1 = playerData[player.Name][slot1]["BulletType"]
			local type2 = playerData[player.Name][slot2]["BulletType"]
			if type1 ~= nil and type2 ~= nil and type1 == type2 then
				fillMag(player, slot1, slot2)
				playFill:FireClient(player)
			end
		end
		
		
		-- Tell the client to update their inventory
		if debugMode then
			requestInventoryUpdate:FireClient(player, retrieveTable(player), getMaxSlots(player))
			refreshSlot:FireClient(player, slot1, playerData[player.Name][slot1])
		else
			refreshSlot:FireClient(player, slot1, playerData[player.Name][slot1])
			refreshSlot:FireClient(player, slot2, playerData[player.Name][slot2])
		end
		
		
		--requestInventoryUpdate:FireClient(player, retrieveTable(player), getMaxSlots(Player))
		
	end

end

I read the first bit of the script but I really don’t want to read all of it, sorry. My suggestion is that you make a class out of this script, something like PlayerDataManager. then you’d define all the functions in seperate modules, as children of the PlayerDataManager module. Something like this:

local PDM = {}
PDM.__index = PDM

PDM.playerData = {}
PDM.getMaxSlots = require(script.getMaxSlots)

return PDM

And the getMaxSlots module would be:

function getMaxSlots()
	-- Code to get max slots
end

return getMaxSlots```
3 Likes

This should go into Code Review, not Scripting Support.

Since this script is in the server, you can cut down all the WaitForChild you do. The server should have all its instances loaded by the time your script begins running, so you only need to use WaitForChild on things that other scripts will create.

You don’t need to do tonumber(0xfff...etc) and such by the way, those are already numeric literals.

You don’t need to force in OOP to make this modular. Just splitting the functions into different modules without using metatables will do the trick.

5 Likes

Thank you! I didn’t know code review was a thing :ok_hand:

1 Like