[IGS] Пример автоматического конвертера донат-валюты в игровой баланс сервера

Выкладываю пример кода для автоматического конвертера IGS-коинов сразу в игровую валюту.

На случай, если не хотите использовать встроенный магазин товаров IGS или есть необходимость в прямой конвертации IGS-коинов в свою игровую валюту сервера.

Как это работает:

  1. Система получает баланс игрока, и конвертирует его в зависимости от игровых пакетов/наборов которые вы продаете (например чтобы за 10000 IGS-коинов давало 15000 игровой валюты, за 5000 IGS-иконов - 6000 игровой валюты и тд).
  2. Оставшийся баланс, который система не смогла потратить на наборы/пакеты конвертируется по курсу (допустим 1 IGS-коин = 1.2 валюты).

Целью стояла реализация системы без привязки к хуку платежа (без extra для IGS.PaymentStatusUpdated). Поэтому если игрок купил 10000 IGS-иконов, и не потратил их вовремя/не списались автоматически, а вы успели поменять курс - при следующем входе на сервер IGS-коины сконвертируется по новому курсу.

На основе этого кода Вы можете сделать и проще - например конвертацию валюты 1 к 1.

GitHub: GitHub - FosterZRussian/IGS-Wallet-Converter-Example

-- IGS (https://gm-donate.net) 
-- Пример автоматического конвертера баланса в игровую валюту по игровым наборам/пакетам.

-- Обратите внимание, этот пример кода взят с моего личного проекта. 
-- Для вашего игрового сервера вам необходимо использовать свои функции для уведомлений/выдачи игровой валюты игроку (svdb.players.GiveWallet, ply:ShowMsg) 


-- Пример конфига для игровых наборов
UI = {}
UI.ShopDonatePackages = {}
local function add_price(price, reward)
	table.insert(UI.ShopDonatePackages,  { reward = reward, price = price } )
end

add_price(78, 78)
add_price(145, 145)
add_price(399, 450)
add_price(750, 900)
add_price(1450, 1800)
add_price(3900, 5000)
add_price(9750, 13500)

UI.ShopDonatePackagesReversed = {}
local DonatePackagesCount = #UI.ShopDonatePackages
for i = 1, DonatePackagesCount do
	UI.ShopDonatePackagesReversed[ (DonatePackagesCount-i) + 1 ] = UI.ShopDonatePackages[i]
end


local AlreadyChecking = {}

-- Наша функция для проверки игрока (можем вызывать в момент пополнения баланса/авторизации на игровом сервере)
function IGS_CheckCredits(ply)
	local s64 = ply:SteamID64()
	
	-- Предотвращаем просчет игрока если его баланс уже считается
	if AlreadyChecking[s64] then return end
	AlreadyChecking[s64] = true

	-- Получаем баланс игрока
	IGS.GetBalance(s64, function(real_balance)
		real_balance = real_balance or 0

		-- Не считаем игрока если у него нулевой баланс
		if real_balance == 0 then 
			AlreadyChecking[s64] = false
			return 
		end
		
		local give_game_wallet = 0		
		local balance_left = real_balance

		-- Определяем сколько баланса можно сконвертировать по игровым наборам
		print('Calcing packages:')
		for k,v in ipairs(UI.ShopDonatePackagesReversed) do -- Бегаем от самого высокого игрового набора, до самого низкого, чтобы сконвертировать на выгодных условиях
			if balance_left < v.price then continue end

			-- Определяем, сколько "таких" игровых наборов игрок может получить за текущий баланс
			local give_packages_count = math.floor(balance_left / v.price)
			if give_packages_count == 0 then continue end

			local take_balance_by_packages = give_packages_count * v.price
			local give_game_wallet_by_packages = (give_packages_count * v.reward)
				
			print('\t Take balance', take_balance_by_packages)
			print("\t\t Give wallet", give_game_wallet_by_packages)
			
			give_game_wallet = give_game_wallet + give_game_wallet_by_packages
			balance_left = balance_left - take_balance_by_packages
		end
		

    
		local final_exchange_rate = 0.5
		local final_exchange_reward = 1
		-- Определяем сколько финального баланса можно сконвертировать по курсу 0.5 (баланса) к 1 (игровых монет)		
		local final_convert_count = math.floor(balance_left / final_exchange_rate)

    -- Пытаемся сконвертировать оставшуюся валюту
		if final_convert_count > 0 then
			print('Calcing final convert:')
			local take_balance_by_final_convert = final_convert_count * final_exchange_rate -- Сколько забираем (0.5 баланса)
			local give_wallet_by_final_convert = final_convert_count * final_exchange_reward -- Сколько даем (для примера 1 игровая монета за каждые 0.5 баланса)

			print("\t Take balance", take_balance_by_final_convert)		
			print("\t\t Give wallet", give_wallet_by_final_convert)
			
			give_game_wallet = give_game_wallet + give_wallet_by_final_convert
			balance_left = balance_left - take_balance_by_final_convert
		end
		

		print("----------")
		
		print("Real balance", real_balance)
		local take_balance = real_balance-balance_left		
		print("Left balance (potential)", balance_left) -- Принт для проверки, чтобы убедиться что наши копейки не сконвертировались в пустоту


		
		-- Отнимаем просчитанный баланс
		IGS.Transaction(s64, -take_balance, "Конвертация " .. take_balance .. " руб.  в игровую валюту", function(trans_id)			
			print("Take balance", take_balance)		
			
			-- Выдаем нашу игровую валюту
			svdb.players.GiveWallet(ply, "p_crd", give_game_wallet, function() -- (используйте вашу функцию)			
				print("Give wallet", give_game_wallet)
				
				-- Делаем лог в IGS, на случай если у нас что-то где-то сломается и нужны будут логи об "успешности"
				IGS.Transaction(s64, 0, "Успешно выдано " .. give_game_wallet .. " игровой валюты [#" .. trans_id .. "]")
				-- Тут же желательно сделать лог  уже в нашу БД.				

				-- Отправляем уведомление игроку 
				if IsValid(ply) then
					ply:ShowMsg("Зачислено " .. give_game_wallet .. " кредитов.") -- (используйте вашу функцию)
				end
				
				-- Успешно посчитали игрока, разрешаем следующие просчеты
				AlreadyChecking[s64] = false 
			end)
		end)

	end)
end


hook.Add("IGS.PaymentStatusUpdated", "GM-Donate.ThanksForDonate", function(pl, tbl)
	IGS_CheckCredits(pl)
end)

Круто, вы создали тему. К сожалению, большинство тем на этом форуме модераторам приходится переименовывать и удалять, чтобы поддерживать форум в чистоте.

  1. Если ваша тема содержит заголовок, по которому ее невозможно найти через поиск или который не несет конкретики, например “помогите с ошибкой” вместо например “[DarkRP] Не создается коробка с оружием при нажатии кнопки”, то тема будет либо отредактирована, либо удалена
  2. Код в теме и логи следует обрамлять тремя такими символами: ```. Сверху кода и снизу. Тогда он будет выглядеть красиво, а не как каша текста
  3. Сверху ссылка на методичку модератора. Если вы ее прочтете, то круто поможете форуму. Кто знает, может именно вы будущий модератор?