Как преодолеть 32 бита для хранения таких номеров, как - от 2 147 483 647 до 2 147 483 647 - PullRequest
0 голосов
/ 04 июля 2019

Я пытаюсь исправить какой-то старый скрипт Basewars для Gmod, и кое-что я пытался исправить, но я не знаю, чего мне там не хватает.В основном это о банковском сценарии.Этот банк мог изначально хранить сумму в 2 миллиарда долларов.Я хотел бы увеличить объем хранилища до 1 квадриллиона.

Итак, в основном, мод Basewars позволяет игрокам иметь большое количество денег до 10 ^ 18 $ = 1 квинтиллион.Я посмотрел на https://wiki.garrysmod.com/page/Category:number

, поэтому в основном lua использует формат с плавающей запятой двойной точности.Таким образом, lua использует 32 бита для хранения чисел, и это означает, что число может быть в диапазоне от -2 147 483 647 до 2 147 483 647

1007 * В режиме Basewars Game используется функция для получения 10 ^ 18 = 1 квинтиллиона
function BaseWars.NumberFormat(num)

    local t = BaseWars.LANG.Numbers
    for i = 1, #t do

        local Div = t[i][1]
        local Str = t[i][2]

        if num >= Div or num <= -Div then

         return string.Comma(math.Round(num / Div, 1)) .. " " .. Str

        end

    end

    return string.Comma(math.Round(num, 1))

end

Gamemode использует эту фракцию для конвертации суммы денег.а вот BaseWars.LANG.Numbers:

BaseWars.LANG = {}
BaseWars.LANG.__LANGUAGELOOK = {}

BaseWars.LANG.__LANGUAGELOOK.ENGLISH = {
    Numbers = {
        [5] = {10^6, "Million"},
        [4] = {10^9, "Billion"},
        [3] = {10^12, "Trillion"},
        [2] = {10^15, "Quadtillion"},
        [1] = {10^18, "Quintillion"},
    },

    CURFORMER       = CURRENCY .. "%s",
    CURRENCY        = CURRENCY,
}

Так что я знаю, что эта функция работает, но я не понимаю, как может быть столь высокая переменная num!Почему я знаю, что это работает?

Вот то, что я пытался, и он манипулировал мощностью до 1 квадриллиона, но в тот момент, когда я манипулировал другой проблемой, возникла проблема, и я не знаю, что я делаю неправильно!

Вот как это было Оригинально:

ENT.Capacity        = 2000000000 --Max money in the bank. Can be bugs if it is more than 2000000000 (2 bil)
ENT.Money           = 0
ENT.MaxPaper        = 0

local Clamp = math.Clamp
function ENT:GSAT(slot, name,  min, max)

    self:NetworkVar("Int", slot, name)

    local getVar = function(minMax)

        if self[minMax] and isfunction(self[minMax]) then return self[minMax](self) end
        if self[minMax] and isnumber(self[minMax]) then return self[minMax] end

        return minMax or 0

    end

    self["Add" .. name] = function(_, var)

            local Val = self["Get" .. name](self) + var

            if min and max then

                Val = Clamp(tonumber(Val) or 0, getVar(min), getVar(max))

            end

            self["Set" .. name](self, Val)

    end

    self["Take" .. name] = function(_, var)

        local Val = self["Get" .. name](self) - var

        if min and max then

            Val = Clamp(tonumber(Val) or 0, getVar(min), getVar(max))

        end

        self["Set" .. name](self, Val)

    end

end


function ENT:StableNetwork()

    self:GSAT(2, "Capacity")

    self:GSAT(3, "Money", 0, "GetCapacity")
    self:GSAT(4, "Paper", 0, "MaxPaper")
    self:GSAT(5, "Level", 0, "MaxLevel")

end

function ENT:ThinkFunc() --This Funtion is to auto collect all the Money of Printers 


for k, v in pairs( ents.FindByClass( "bw_printer_*" ) ) do 
            if v:CPPIGetOwner() == self:CPPIGetOwner() then
                if self:GetMoney() < self.Capacity then
                    local allmoney = v:GetMoney()
                    v:TakeMoney(allmoney)
                    self:AddMoney(allmoney)
                end
            end
        end     

        for k, v in pairs( ents.FindByClass( "bw_base_moneyprinter" ) ) do
            if v:CPPIGetOwner() == self:CPPIGetOwner() then
                if self:GetMoney() < self.Capacity then
                    local allmoney = v:GetMoney()
                    v:TakeMoney(allmoney)
                    self:AddMoney(allmoney)
                end
            end
        end 

end

if CLIENT then
local Cp = self:GetCapacity()
local money = tonumber(self:GetMoney()) or 0
        local cap = tonumber(Cp) or 0

        local moneyPercentage = math.Round( money / cap * 100 ,1)

        draw.DrawText( moneyPercentage .."%" , fontName .. ".Huge", w - 4-430, 71+610, self.FontColor, TEXT_ALIGN_CENTER)

local currentMoney = BaseWars.LANG.CURRENCY .. BaseWars.NumberFormat(money)
            local maxMoney = BaseWars.LANG.CURRENCY .. BaseWars.NumberFormat(cap)
            local font = fontName .. ".Big"
            if #currentMoney > 16 then

                font = fontName .. ".MedBig"

            end
            if #currentMoney > 20 then

                font = fontName .. ".Med"

            end
            local fh = draw.GetFontHeight(font)

            local StrW,StrH = surface.GetTextSize("")
            local moneyW,moneyH = surface.GetTextSize(currentMoney)
            draw.DrawText(currentMoney.. " / " .. BaseWars.LANG.CURRENCY .. BaseWars.NumberFormat(cap) , font,
                w/2 - StrW/2-225 , (font == fontName .. ".Big" and 106 or 105 + fh / 4)+675, self.FontColor, TEXT_ALIGN_CENTER)


end

Вот изменения, которые я сделал:

удалённая строка: локальная заглушка = номер (Cp) или 0

добавлен локальный cap = 10 ^ 15, если self: GetMoney ()

ENT.Capacity        = 2000000000 --Max money in the bank. Can be bugs if it is more than 2000000000 (2 bil)
local cap = 10^15
ENT.Money           = 0
ENT.MaxPaper        = 0

local Clamp = math.Clamp
function ENT:GSAT(slot, name,  min, max)

    self:NetworkVar("Int", slot, name)

    local getVar = function(minMax)

        if self[minMax] and isfunction(self[minMax]) then return self[minMax](self) end
        if self[minMax] and isnumber(self[minMax]) then return self[minMax] end

        return minMax or 0

    end

    self["Add" .. name] = function(_, var)

            local Val = self["Get" .. name](self) + var

            if min and max then

                Val = Clamp(tonumber(Val) or 0, getVar(min), getVar(max))

            end

            self["Set" .. name](self, Val)

    end

    self["Take" .. name] = function(_, var)

        local Val = self["Get" .. name](self) - var

        if min and max then

            Val = Clamp(tonumber(Val) or 0, getVar(min), getVar(max))

        end

        self["Set" .. name](self, Val)

    end

end


function ENT:StableNetwork()

    self:GSAT(2, "Capacity")

    self:GSAT(3, "Money", 0, "GetCapacity")
    self:GSAT(4, "Paper", 0, "MaxPaper")
    self:GSAT(5, "Level", 0, "MaxLevel")

end

function ENT:ThinkFunc() --This Funtion is to auto collect all the Money of Printers 


for k, v in pairs( ents.FindByClass( "bw_printer_*" ) ) do 
            if v:CPPIGetOwner() == self:CPPIGetOwner() then
                if self:GetMoney() < cap then
                    local allmoney = v:GetMoney()
                    v:TakeMoney(allmoney)
                    self:AddMoney(allmoney)
                end
            end
        end     

        for k, v in pairs( ents.FindByClass( "bw_base_moneyprinter" ) ) do
            if v:CPPIGetOwner() == self:CPPIGetOwner() then
                if self:GetMoney() < cap then
                    local allmoney = v:GetMoney()
                    v:TakeMoney(allmoney)
                    self:AddMoney(allmoney)
                end
            end
        end 

end

if CLIENT then
local Cp = self:GetCapacity()
local money = tonumber(self:GetMoney()) or 0


        local moneyPercentage = math.Round( money / cap * 100 ,1)

        draw.DrawText( moneyPercentage .."%" , fontName .. ".Huge", w - 4-430, 71+610, self.FontColor, TEXT_ALIGN_CENTER)

local currentMoney = BaseWars.LANG.CURRENCY .. BaseWars.NumberFormat(money)
            local maxMoney = BaseWars.LANG.CURRENCY .. BaseWars.NumberFormat(cap)
            local font = fontName .. ".Big"
            if #currentMoney > 16 then

                font = fontName .. ".MedBig"

            end
            if #currentMoney > 20 then

                font = fontName .. ".Med"

            end
            local fh = draw.GetFontHeight(font)

            local StrW,StrH = surface.GetTextSize("")
            local moneyW,moneyH = surface.GetTextSize(currentMoney)
            draw.DrawText(currentMoney.. " / " .. BaseWars.LANG.CURRENCY .. BaseWars.NumberFormat(cap) , font,
                w/2 - StrW/2-225 , (font == fontName .. ".Big" and 106 or 105 + fh / 4)+675, self.FontColor, TEXT_ALIGN_CENTER)


end

Так что теперь, если я смотрю в игру, она выглядит так: и теперь у меня проблема в том, что при сбореденьги это делает до 2 миллиардов, и если я пытаюсь изменить

local money = tonumber(self:GetMoney()) or 0

на

local money =self:GetMoney()

, я получаю прямую -2,1 Bil

или я пытался изменитьминимальные максимальные значения:

function ENT:GSAT(slot, name,  min, max)

    self:NetworkVar("Int", slot, name)

    local getVar = function(minMax)

        if self[minMax] and isfunction(self[minMax]) then return self[minMax](self) end
        if self[minMax] and isnumber(self[minMax]) then return self[minMax] end

        return minMax or 0

    end

    self["Add" .. name] = function(_, var)

            local Val = self["Get" .. name](self) + var

            if min and max then

                Val = Clamp(tonumber(Val) or 0, getVar(min), 10^15)

            end

            self["Set" .. name](self, Val)

    end

    self["Take" .. name] = function(_, var)

        local Val = self["Get" .. name](self) - var

        if min and max then

            Val = Clamp(tonumber(Val) or 0, getVar(min), 10^15)

        end

        self["Set" .. name](self, Val)

    end

end

В основном эти строки:

Val = Clamp(tonumber(Val) or 0, getVar(min), 10^15)

, если я запускаю игру, Банк просто соберет деньги до 2 Биллов, а затем до -2.1Бил.И в этот момент я не знаю, почему и когда значение действительно глючит, как будто само устанавливается на -2,1 млрд.math.Round создает эту ошибку или функция возвращает только возвращаемое целое число?

спасибо за любую помощь

1 Ответ

0 голосов
/ 13 июля 2019

Поскольку сетевая переменная, которую использует банк, является целым числом, он сможет хранить только $ (2 ^ 31-1) - $ - (2 ^ 31-1). Попробуйте изменить его на сетевой с плавающей точкой:

-- ...
function ENT:GSAT(slot, name,  min, max)

    -- self:NetworkVar("Int", slot, name), changes into:
    self:NetworkVar("Float", slot, name)
-- ...

Но будьте осторожны, поскольку чем больше игроков накапливает деньги, тем меньше точности будет добавлено к этим числам.

...