Перейти к содержимому

Робот Байт

  • записей
    5
  • комментария
    54
  • просмотров
    22 166

Цифровой "Банк опыта" в Майнкрафт.

Alex

2 444 просмотра

Некоторое время назад обнаружил мод Exp Chest.
Для версии 1.7.10, как и в частности для режима мультиплеера, судя по всему, этого мода нет в принципе. Вот и появилась "хотелка" реализовать данный мод на сервере в виде Админ-хранилища.

 

Игроки смогут весь опыт быстренько сгрузить на хранение или взять (весь или его часть, как угодно) Значение банковских ячеек привязано к базе SQL.

 

На проекте также ведется разработка данной программы игроком Asummonster и, возможно, др. игроками. Вариант реализации можно посмотреть здесь.

 

 

 


Эту программку я сделал так, как ее представил с самого начала и просил игроков, максимально повторить мод.

 

Видео: ВИДЕО
Версия 0.1.1: http://pastebin.com/ASu4szwH

 

Код: (реальные пароли и имя скрипта спрятаны в целях безопасности):

------------------------------------------------------                    Программа                   --  --         для хранения опыта в Майнкрафт         ----            с привязкой к базе SQL              --  --          проект http://computercraft.ru        --  --                 2015, © AlexCC                 --  ----------------------------------------------------local event=require("event")local term=require("term")local unicode=require("unicode")local computer=require("computer")local component=require("component")local radar=component.openperipheral_sensorlocal cb=component.command_blocklocal gpu=component.gpulocal inet = component.internetgpu.setDepth(4)-- константыlocal VERSION = "0.1.1"local KEY = '1111111qwerty55555'-- Varlocal expPers = 0local expBank = 0local CLIENT = nillocal TRANSFERCOUNT  = 50-- ========= Кнопки ============ --Button = {}Button.__index = Buttonfunction Button.new(func, x, y, text, fore, back, width, nu)	self = setmetatable({}, Button)	self.form = '[ '	if width == nil then width = 0	    else width = (width - unicode.len(text))-4 	end	for i=1, math.floor(width/2) do	    self.form = self.form.. ' '	end	self.form = self.form..text	for i=1, math.ceil(width/2) do	    self.form = self.form.. ' '	end	self.form = self.form..' ]'	self.func = func	self.x = math.floor(x); self.y = math.floor(y)	self.fore = fore	self.back = back	self.visible = true	self.notupdate = nu or false	return selfendfunction Button:draw(fore, back)	if self.visible then	    local fore = fore or self.fore	    local back = back or self.back	    gpu.setForeground(fore)	    gpu.setBackground(back)	    gpu.set(self.x, self.y, self.form)	endendfunction Button:click(x, y)    if self.visible then	    if y == self.y then	        if x >= self.x and x < self.x + unicode.len(self.form) then		        self:draw(self.back, self.fore)		        local data = self.func()		        if not self.notupdate then self:draw() end		        return true, data	        end	    end    end  return falseendfunction buttonNew(buttons, func, x, y, text, fore, back, width, notupdate)  	button = Button.new(func, x, y, text, fore, back, width, notupdate)  	table.insert(buttons, button)  	return buttonendfunction buttonsDraw(buttons)  	for i=1, #buttons do    	buttons[i]:draw()  	endendfunction buttonsClick(buttons, x, y)	for i=1, #buttons do	    ok, data = buttons[i]:click(x, y)		if ok then return data end	end	return nilend--===================================--function setCenterText(y, w, text)	len=unicode.len(text)	local x=(w/2)-(len/2)	gpu.set(x, y, text)endfunction runCommand(str) -- наша КБ-шка, куда же без нее	cb.setCommand(str)	cb.executeCommand()endfunction get(url) -- получить ответ от сервера (опыт из базы SQL)  local request, reason = inet.request(url)  if not request then return false end  local text = ''	  	while true do		    local data, reason = request.read()		    if not data then		      request.close()		      break		    elseif #data > 0 then		      text = text..data		    end	  	end  return textendfunction getBankExp(nick)  -- получение значения  опыта в банке (SQL)	return get('http://computercraft.ru/.../*************.php?type=exp&auth='..KEY..'&nick='..nick..'&action=get')endfunction addBankExp(nick, amount) -- прибавить опыт на счет (SQL)	return get('http://computercraft.ru/.../*************.php?type=exp&auth='..KEY..'&nick='..nick..'&action=add&value='..amount)endfunction giveUserExp(nick, exp) -- выдать опыт клиенту через КБ	runCommand("xp "..exp.." "..nick)endfunction setNullUserExp(nick, lvl)  -- обнулить опыт клиенту	runCommand("xp -"..lvl.."L "..nick)endfunction getUserExp(nick)   -- получить текущий опыт клиента (радар OpenPeripheral)	local currentExp	local exp  = radar.getPlayerByName(nick).all().player.experience	if exp.level >= 31 then		currentExp =  3.5*exp.level^2-151.5*exp.level+2220	elseif exp.level >= 16 and exp.level <= 30 then		currentExp = 1.5*exp.level^2 - 29.5*exp.level + 360	elseif exp.level<=15 then 		currentExp = 17*exp.level	end	-- вернем полный опыт в абсолютных единицах, а также текущий уровень	return math.floor(exp.levelProgress*exp.nextLevelXp + currentExp) , exp.levelendfunction  clearSetScr(x,y) -- чистим экранчик	gpu.setForeground(0xffffff)	gpu.setBackground(0x000000)	gpu.setResolution(x,y)	term.clear()end	function drawGuestWindow()  -- рисуем гостевое окошко, чистим пользователей, трансфер в "серединку"	users={computer.users()}	for i=1, #users do		computer.removeUser(users[i])	end	clearSetScr(44,20)	gpu.setForeground(0x0000ff)	print([[	  ______             _    	  | ___ \           | |   	  | |_/ / __ _ _ __ | | __	  | ___ \/ _` | '_ \| |/ /	  | |_/ / (_| | | | |   < 	  \____/ \__,_|_| |_|_|\_\	       _____    ______        	      |  ___|   | ___ \       	      | |____  _| |_/ /       	      |  __\ \/ /  __/        	      | |___>  <| |           	      \____/_/\_\_|  	]])	gpu.setForeground(0x0000ff)	setCenterText(18, 44,' Банк опыта ☭, ©AlexCC')	setCenterText(19,44,' Проект http://computercraft.ru, 2015')	buttonsDraw(guestButtons)	TRANSFERCOUNT = 50endfunction drawMineWindow()  -- рисуем основное окошко для трансфера, лочим ПК на клиента	computer.addUser(CLIENT)	expPers, current_lvl = getUserExp(CLIENT)	expBank = getBankExp(CLIENT)	clearSetScr(40,14)	gpu.setBackground(0x1e1e1e)	gpu.fill(1,1,40,6,' ')	gpu.setForeground(0xffffff)	setCenterText(2,40,' Привет, '..CLIENT..'!')	gpu.setForeground(0xffdb00)	gpu.set(6,3,'Ваш опыт в Банке:      '..expBank..' ед.')	gpu.set(6,4,'Ваш текущий опыт:      '..expPers..' ед.')	gpu.set(6,5,'Ваш текущий уровень:   '..current_lvl)	gpu.set(1,1,"╔")	gpu.set(40,1,"╗")	gpu.set(1,6,"╚")	gpu.set(40,6,"╝")	for i  = 2, 5 do		gpu.set(1, i,"║")		gpu.set(40, i,"║")	end	gpu.set(2,1, string.rep("═",38))	gpu.set(2,6, string.rep("═",38))	gpu.setBackground(0x000000)	gpu.setForeground(0xffffff)	gpu.set(19, 8, TRANSFERCOUNT..' %')	buttonsDraw(menuButtons)endfunction  transferExpToUser() -- клиент снимает с банка опыт	expPers, current_lvl = getUserExp(CLIENT) -- уточним еще раз опыт клиента, он мог измениться при открытой сессии(клиент выпил бутылочку опыта или убил паука рядом)	local trans_exp = math.floor(TRANSFERCOUNT * expBank/100)	giveUserExp(CLIENT, trans_exp)	addBankExp(CLIENT, -trans_exp) 	drawMineWindow()endfunction  transferExpToBank() -- клиент отправляет опыт в банк на хранение	expPers, current_lvl = getUserExp(CLIENT)	local trans_exp = math.floor(TRANSFERCOUNT * expPers/100)	setNullUserExp(CLIENT, current_lvl + 1) -- обнулим весь опыт 	giveUserExp(CLIENT, expPers - trans_exp) -- и выдадим разницу, что было и что отправлено	addBankExp(CLIENT, trans_exp) -- отправим в банк опыт игрока, который он выбрал в процентном соотношении	drawMineWindow()endfunction min1()  -- уменьшить значение трансфера    TRANSFERCOUNT = TRANSFERCOUNT - 1    if TRANSFERCOUNT < 0 then TRANSFERCOUNT = 0 end    drawTransfer()endfunction min10() -- уменьшить значение трансфера    TRANSFERCOUNT = TRANSFERCOUNT - 10    if TRANSFERCOUNT < 0 then TRANSFERCOUNT = 0 end    drawTransfer()endfunction plus1() -- увеличить значение трансфера    TRANSFERCOUNT = TRANSFERCOUNT + 1    if TRANSFERCOUNT > 100 then TRANSFERCOUNT = 100 end    drawTransfer()endfunction plus10() -- увеличить значение трансфера    TRANSFERCOUNT = TRANSFERCOUNT + 10    if TRANSFERCOUNT > 100 then TRANSFERCOUNT = 100 end    drawTransfer()endfunction drawTransfer() -- нарисовать текущее значение процентика перевода опыта    gpu.setForeground(0xffffff)    gpu.setBackground(0x000000)    gpu.fill(19,8, 5, 1,' ')    gpu.set(19, 8, TRANSFERCOUNT..' %')endfunction operatiOnOnBank() -- цикл операций с опытом, пока не сдохнет ивентпулл или клиент не выйдет в гостевое окно	drawMineWindow()	while true do	local name, address, x, y = event.pull(60, 'touch')	  	if name == 'touch' then	    	local result = buttonsClick(menuButtons, x, y)	    	if result == 'exit' then break end	  	else	  		break	  	end  	endend-- тут будут храниться кнопки (группы кнопок)menuButtons = {}guestButtons = {}-- рисуем кнопкиbuttonNew(guestButtons, operatiOnOnBank, 13, 15, " НАЧАТЬ РАБОТУ ", 0xFFFFFF, 0x0000FF, 11)buttonNew(menuButtons, min10, 2, 8, "-10", 0xFFFFFF, 0x0000FF, 4)buttonNew(menuButtons, min1, 10, 8, "-1", 0xFFFFFF, 0x0000FF, 4)buttonNew(menuButtons, plus1, 26, 8, "+1", 0xFFFFFF, 0x0000FF, 4)buttonNew(menuButtons, plus10, 33, 8, "+10", 0xFFFFFF, 0x0000FF, 4)buttonNew(menuButtons, transferExpToBank, 8, 10, " Положить опыт в Банк  ", 0xFFFFFF, 0x0000FF, 20)buttonNew(menuButtons, transferExpToUser, 8, 12, " Забрать опыт из Банка ", 0xFFFFFF, 0x0000FF, 20)buttonNew(menuButtons, function() return 'exit' end, 16, 14, " Выход ", 0xFFFFFF, 0xFF0000, 10)-- главный цикл программы, висит гостевое окно, ПК ни на кого не залоченwhile true do	drawGuestWindow()  	local e, _, x, y, _, nick = event.pull('touch')  	-- если был клик мышкой - проверяем кнопки  	if e == 'touch' then  		CLIENT = nick    	buttonsClick(guestButtons, x, y)  	endend


 

 


ВНИМАНИЕ! В данной реализации программы использовано подключение к SQL. Но можно организовать и локальное файловое хранилище клиентской базы в игре, не используя внешние структуры данных.

 

Код скрипта (пример):

<?php	// Пример запроса на добавление экспы или получение ее текущего значения 	// http://localhost/expupd.php?&auth=f92b3037ee&nick=Alex&action=add&value=10	// http://localhost/expupd.php?&auth=f92b3037ee&nick=Bob&action=add&value=-570	// http://localhost/expupd.php?&auth=f92b3037ee&nick=Bob&action=get		// Получаем переменные в GET запросе:	$username = htmlspecialchars($_GET['nick']);	$action = htmlspecialchars($_GET['action']);	$value = htmlspecialchars($_GET['value']);	$auth = htmlspecialchars($_GET['auth']);		// Проверим пароль доступа к скрипту и и некоторые параметры запроса:		$codeaccess = 'f92b3037ee';	if ($auth !=  $codeaccess)  die ("Wrong auth");	// В имени пользователя могут быть только цифры, буквы и знак нижнего подчеркивания	if (!preg_match("/^[a-zA-Z0-9_]+$/", $username)) die("Bad login");	if ($action != 'set' and $action != 'get' and $action != 'add') die("Wrong action");		// Параметры подключения к базе:	$host = 'localhost';	$user = 'alexcc'; // имя пользователя базы	$pass = 'SFJHwhP6RrSaz'; //пароль к базе	$namebase = 'prog'; // имя базы	$table = 'test'; // имя таблицы		// Подключение к базе	$connect = mysql_connect($host, $user, $pass) or die('error connect');    mysql_select_db($namebase, $connect);	$sql = mysql_query("SELECT exp FROM $table WHERE nick = '$username'") or die (mysql_error());	$count = mysql_num_rows($sql);		// Если такого пользователя нет еще в базе, создадим его, и присвоем значение опыта 0	if ($count == 0) 	{		mysql_query("INSERT INTO $table (`nick`, `exp`, `lastaccess`) VALUES ('$username', '0', NOW())") or die (mysql_error());	} 	// Вернем значение опыта	if($action == 'get')	{		$sql = mysql_query("SELECT exp FROM $table WHERE `nick`='$username'") or die (mysql_error());		$data = mysql_fetch_array($sql);        echo $data['exp'];	}	// Добавим или отнимем (если значение отрицательное) опыт	if($action == 'add')	{		mysql_query("UPDATE $table SET exp = exp + '$value' WHERE `nick`='$username'") or die (mysql_error());		echo 'OK';	}		// Чит фича (установка конкретного значения опыта)	if($action == 'set')	{		mysql_query("UPDATE $table SET exp ='$value' WHERE `nick`='$username'") or die (mysql_error());		echo 'OK';	}	// Закроем соединение с базой	mysql_close($connect);?>


 

 


Пример базы:

 

a1rRrzb.png

 

gPpw4QQ.png

 

9Nqwp68.png

 

В будущем, когда на ИТ будет введено ограничение на использование сложных технологий (например ядерных) игрокам накопитель опыта очень пригодится. Только потратив огромное его количество, игрок сможет получить квалификацию физика-ядерщика и только тогда сможет работать с ядерными технологиями и прочее.

 

Замеченные багульки и неточности просьба оставлять в комментариях.

  • Нравится 4


6 комментариев


Рекомендуемые комментарии

$codeaccess = 'f92b3037ee'; это я так понимаю, ключ?)
(реальные пароли и имя скрипта спрятаны в целях безопасности)

 

А почему используется внешний SQL-сервер. Силами одного ОС-компа это сделать нельзя?

Поделиться комментарием


Ссылка на комментарий

А почему используется внешний SQL-сервер. Силами одного ОС-компа это сделать нельзя?

Идея была хранить опыт также как голоса, доллары, тугрики...

Поделиться комментарием


Ссылка на комментарий

$codeaccess = 'f92b3037ee'; это я так понимаю, ключ?)

Да, это ключ. Это же очевидно. Он передается, как параметр, и если он невалидный, выполнение сценария скрипта прекращается.

Поделиться комментарием


Ссылка на комментарий

А почему используется внешний SQL-сервер. Силами одного ОС-компа это сделать нельзя?

 

Можно, конечно. Но единая база развязывает нам руки и дает возможность создать сеть независимых  банкоматиков опыта по всему миру http://puu.sh/jjwaW/0c45a182fd.jpg, отобразить опыт на сайте. За опыт можно будет приобрести специальности и прочее в будущем.

 

Тут есть уже очень давно "хотелка" локальных роботов, которые по определению локальны и автономны, сделать управление с мобильника или через веб-интерфейса, а уж ПК и подавно законнектить в глобальную сеть. Локальный игровой ПК - прошлый век. Он может и в лаве утонуть, а SQL никуда не денется. Опыт можно хоть в Африку теперь переводить.

Поделиться комментарием


Ссылка на комментарий

А будет покупка опыта? Или хотя-бы банки опыта в банке добавить.

Думаю, если и будет, то - за UU, наверное.

Поделиться комментарием


Ссылка на комментарий

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Добавить комментарий...

×   Вы вставили отформатированное содержимое.   Удалить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отобразить как ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...