```lua
-- garrysmod\lua\autorun\client\money_commands.lua
local MoneySystem = include("modules/money_system.lua")

util.AddNetworkString = util.AddNetworkString or function() end -- защита, если вызывается на клиенте, нет
-- (AddNetworkString не нужен на клиенте)

-- Команда сброса денег
concommand.Add("dropmoney", function(cmd, args)
    local amount = tonumber(args[1])
    if not amount or amount <= 0 then
        chat.AddText(Color(255, 50, 50), "[Money] Неверная сумма для сброса.")
        return
    end

    net.Start("MoneyDrop_SpawnRequest")
    net.WriteUInt(math.floor(amount), 32)
    net.SendToServer()
end)

-- Команда передачи денег: transfermoney <часть ника> <сумма>
concommand.Add("transfermoney", function(cmd, args)
    if #args < 2 then
        chat.AddText(Color(255, 255, 0), "[Money] Использование: transfermoney <часть ника> <сумма>")
        return
    end

    local targetName = args[1]:lower()
    local amount = tonumber(args[2])
    if not amount or amount <= 0 then
        chat.AddText(Color(255, 50, 50), "[Money] Неверная сумма.")
        return
    end

    local target

    for _, ply in ipairs(player.GetAll()) do
        if string.find(ply:Nick():lower(), targetName, 1, true) then
            target = ply
            break
        end
    end

    if not IsValid(target) then
        chat.AddText(Color(255, 50, 50), "[Money] Игрок не найден.")
        return
    end

    net.Start("MoneyTransfer_Request")
    net.WriteEntity(target)
    net.WriteUInt(math.floor(amount), 32)
    net.SendToServer()
end)
```
```lua
-- garrysmod\lua\entities\money_drop.lua
ENT.Type = "anim"
ENT.Base = "base_anim"
ENT.PrintName = "Money Drop"
ENT.Author = "YourName"
ENT.Spawnable = false
ENT.AdminOnly = false

AccessorFunc(ENT, "m_iAmount", "Amount", FORCE_NUMBER)

if SERVER then
    function ENT:Initialize()
        self:SetModel("models/props_c17/BriefCase001a.mdl")
        self:PhysicsInit(SOLID_VPHYSICS)
        self:SetMoveType(MOVETYPE_VPHYSICS)
        self:SetSolid(SOLID_VPHYSICS)
        self:SetUseType(SIMPLE_USE)

        local phys = self:GetPhysicsObject()
        if phys:IsValid() then
            phys:Wake()
            phys:SetMass(5)
        end
    end

    function ENT:SetAmount(amount)
        amount = math.floor(amount)
        self.m_iAmount = math.max(amount, 0)
    end

    function ENT:GetAmount()
        return self.m_iAmount or 0
    end

    function ENT:Use(activator, caller)
        if IsValid(activator) and activator:IsPlayer() then
            net.Start("MoneyDrop_Pickup")
            net.WriteEntity(self)
            net.Send(activator)
        end
    end
end

if CLIENT then
    function ENT:Draw()
        self:DrawModel()
        local ang = LocalPlayer():EyeAngles()
        local pos = self:GetPos() + Vector(0, 0, 20)

        cam.Start3D2D(pos, Angle(0, ang.y - 90, 90), 0.25)
            draw.SimpleText("💰 " .. tostring(self:GetAmount()), "Trebuchet24", 0, 0, Color(255, 215, 0), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
        cam.End3D2D()
    end
end
```
```lua
-- garrysmod\lua\modules\money_system.lua
local MoneySystem = {}
MoneySystem.__index = MoneySystem

MoneySystem.NETMSG             = "MoneySystem_Update"
MoneySystem.DEFAULT_START_MONEY = 1000
MoneySystem._cache = setmetatable({}, { __mode = "k" })

local _initialized = false

if SERVER then
    util.AddNetworkString(MoneySystem.NETMSG)
end

-- Инициализация
function MoneySystem:Init()
    if _initialized then return end
    _initialized = true

    if SERVER then
        hook.Add("PlayerInitialSpawn", "MoneySystem_LoadPlayerMoney", function(ply)
            self:_LoadPlayerMoney(ply)
        end)

        hook.Add("PlayerDisconnected", "MoneySystem_SavePlayerMoney", function(ply)
            self:_SavePlayerMoney(ply)
            self._cache[ply] = nil
        end)
    end
end

function MoneySystem:_LoadPlayerMoney(ply)
    if not IsValid(ply) or not ply:IsPlayer() then return end

    local savedMoney = ply:GetPData("MoneySystem_Money", nil)
    local money = tonumber(savedMoney)
    if not money or money < 0 then
        money = self.DEFAULT_START_MONEY
    else
        money = math.floor(money)
    end

    self._cache[ply] = money
    ply:SetNWInt("MoneySystem_Money", money)

    hook.Run("MoneySystem_MoneyChanged", ply, money)
end

function MoneySystem:_SavePlayerMoney(ply)
    if not IsValid(ply) or not ply:IsPlayer() then return end
    local money = self._cache[ply] or ply:GetNWInt("MoneySystem_Money", self.DEFAULT_START_MONEY)
    ply:SetPData("MoneySystem_Money", tostring(money))
end

function MoneySystem:GetMoney(ply)
    if SERVER then
        if not IsValid(ply) or not ply:IsPlayer() then return 0 end
        return self._cache[ply] or self.DEFAULT_START_MONEY
    else
        ply = ply or LocalPlayer()
        if not IsValid(ply) then return 0 end
        return ply:GetNWInt("MoneySystem_Money", self.DEFAULT_START_MONEY)
    end
end

function MoneySystem:SetMoney(ply, amount)
    if not IsValid(ply) or not ply:IsPlayer() then return false, "Invalid player" end
    if type(amount) ~= "number" or amount < 0 then return false, "Invalid amount" end

    local newAmount = math.floor(amount)

    if self._cache[ply] == newAmount then return true end

    self._cache[ply] = newAmount
    ply:SetNWInt("MoneySystem_Money", newAmount)
    self:_SavePlayerMoney(ply)
    self:_SendMoneyUpdate(ply, newAmount)

    hook.Run("MoneySystem_MoneyChanged", ply, newAmount)

    return true
end

function MoneySystem:AddMoney(ply, amount)
    if not IsValid(ply) or not ply:IsPlayer() then return false, "Invalid player" end
    if type(amount) ~= "number" or amount <= 0 then return false, "Invalid amount to add" end

    local currentMoney = self._cache[ply] or self.DEFAULT_START_MONEY
    local newAmount = currentMoney + math.floor(amount)

    return self:SetMoney(ply, newAmount)
end

function MoneySystem:TakeMoney(ply, amount)
    if not IsValid(ply) or not ply:IsPlayer() then return false, "Invalid player" end
    if type(amount) ~= "number" or amount <= 0 then return false, "Invalid amount to take" end

    local currentMoney = self._cache[ply] or self.DEFAULT_START_MONEY
    local takeAmount = math.floor(amount)

    if currentMoney < takeAmount then return false, "Not enough money" end

    local newAmount = currentMoney - takeAmount
    return self:SetMoney(ply, newAmount)
end

function MoneySystem:_SendMoneyUpdate(ply, amount)
    if CLIENT then return end
    if not IsValid(ply) or not ply:IsPlayer() then return end

    net.Start(self.NETMSG)
        net.WriteInt(amount, 32)
    net.Send(ply)
end

-- Унифицированное уведомление
function MoneySystem.Notify(ply, msg)
    if not IsValid(ply) or not ply:IsPlayer() then return end
    ply:ChatPrint("[MoneySystem] " .. tostring(msg))
end

if CLIENT then
    net.Receive(MoneySystem.NETMSG, function()
        local amount = net.ReadInt(32)
        local ply = LocalPlayer()
        if IsValid(ply) then
            ply:SetNWInt("MoneySystem_Money", amount)
            hook.Run("MoneySystem_MoneyChanged", ply, amount)
        end
    end)

    function MoneySystem.GetMoney(ply)
        ply = ply or LocalPlayer()
        if not IsValid(ply) then return 0 end
        return ply:GetNWInt("MoneySystem_Money", MoneySystem.DEFAULT_START_MONEY)
    end
end

if SERVER then
    MoneySystem:Init()
end

return MoneySystem
```
Implement a nice interface on the client and implement interaction with the server part, make an admin command to give out money.