Обучение #39
30
_incl_data/class/DarksLight2/Training/Steps/SecondStep.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DarksLight2\Training\Steps;
|
||||||
|
|
||||||
|
use DarksLight2\Training\StepFactory;
|
||||||
|
|
||||||
|
class SecondStep extends StepFactory
|
||||||
|
{
|
||||||
|
|
||||||
DarksLight2 marked this conversation as resolved
Outdated
|
|||||||
|
public function getTitle(): string
|
||||||
|
{
|
||||||
|
return 'Тест';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMessage(): string
|
||||||
|
{
|
||||||
|
return 'Тест';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getShortName(): string
|
||||||
|
{
|
||||||
|
return 'second_step';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRewards(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -20,7 +20,7 @@ class TrainingManager
|
|||||||
public function __construct(int $user_id)
|
public function __construct(int $user_id)
|
||||||
{
|
{
|
||||||
$this->user_id = $user_id;
|
$this->user_id = $user_id;
|
||||||
|
$this->generateToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -71,15 +71,17 @@ class TrainingManager
|
|||||||
|
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
|
if(!$this->isComplete) {
|
||||||
$path = $_SERVER['DOCUMENT_ROOT'] . '/modules_data/steps/' . $this->short_name . '.php';
|
$path = $_SERVER['DOCUMENT_ROOT'] . '/modules_data/steps/' . $this->short_name . '.php';
|
||||||
|
|
||||||
if(file_exists($path)) {
|
if (file_exists($path)) {
|
||||||
require $path;
|
require $path;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw TrainingException::noRenderingFile();
|
throw TrainingException::noRenderingFile();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -87,19 +89,61 @@ class TrainingManager
|
|||||||
|
|
||||||
private function stepData(string $short_name): object
|
private function stepData(string $short_name): object
|
||||||
{
|
{
|
||||||
return json_decode($this->getDatabaseRecords()->data)->$short_name;
|
$data = $this->getDatabaseRecords()->data;
|
||||||
|
|
||||||
|
if(!isset($data->$short_name)) {
|
||||||
|
$this->updateDatabaseRecord($short_name);
|
||||||
|
$data = $this->getDatabaseRecords()->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getDatabaseRecords()
|
return $data->$short_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function generateToken($length = 16)
|
||||||
DarksLight2 marked this conversation as resolved
Outdated
lopar
commented
Вроде как полностью дублирует метод PassGen::new(). Вроде как полностью дублирует метод PassGen::new().
DarksLight2
commented
не знал о таком, но посмотрю не знал о таком, но посмотрю
|
|||||||
|
{
|
||||||
|
$letters = 'abcdefgmikiHGJKLjkGASysj7603456';
|
||||||
|
|
||||||
|
$token = '';
|
||||||
|
|
||||||
|
for ($i = 0; $i <= $length; $i++) {
|
||||||
|
$token .= $letters[rand(0, strlen($letters))];
|
||||||
|
}
|
||||||
|
|
||||||
|
Db::run('UPDATE user_training SET api_token = ? WHERE user_id = ?', [
|
||||||
|
$token,
|
||||||
|
$this->user_id
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDatabaseRecords(): stdClass
|
||||||
{
|
{
|
||||||
if(!$this->database_records) {
|
if(!$this->database_records) {
|
||||||
$this->database_records = Db::run('SELECT * FROM user_training WHERE user_id = ?', [$this->user_id])
|
$data = Db::run('SELECT * FROM user_training WHERE user_id = ?', [$this->user_id])
|
||||||
DarksLight2 marked this conversation as resolved
lopar
commented
Если нет особой необходимости, лучше использовать стандартный Db::getRows(), для единообразия. Если нет особой необходимости, лучше использовать стандартный Db::getRows(), для единообразия.
DarksLight2
commented
Выбрал этот путь, потому что только одна запись там должна быть. Выбрал этот путь, потому что только одна запись там должна быть.
lopar
commented
Тогда Db::getRow Тогда Db::getRow
|
|||||||
->fetch(PDO::FETCH_OBJ);
|
->fetch(PDO::FETCH_OBJ);
|
||||||
|
|
||||||
|
$this->database_records = new stdClass();
|
||||||
|
|
||||||
|
$this->database_records->user_id = $data->user_id;
|
||||||
|
$this->database_records->api_token = $data->api_token;
|
||||||
|
$this->database_records->data = json_decode($data->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->database_records;
|
return $this->database_records;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function updateDatabaseRecord(string $short_name)
|
||||||
|
{
|
||||||
|
if($this->getDatabaseRecords()) {
|
||||||
|
|
||||||
|
$this->database_records->data->$short_name = $this->firstRecordData()->$short_name;
|
||||||
|
|
||||||
|
Db::run('UPDATE user_training SET data = ? WHERE user_id = ?', [
|
||||||
DarksLight2 marked this conversation as resolved
Outdated
lopar
commented
Db:sql() Db:sql()
DarksLight2
commented
А смысл, если этот метод все равно вызывает run?) А смысл, если этот метод все равно вызывает run?)
lopar
commented
run изначально приватный медод, который cтал публичным потому что где-то в паре мест понадобился доступ к PDOStatement. run изначально приватный медод, который cтал публичным потому что где-то в паре мест понадобился доступ к PDOStatement.
|
|||||||
|
json_encode($this->database_records->data),
|
||||||
|
$this->user_id
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function createDatabaseRecord()
|
public function createDatabaseRecord()
|
||||||
{
|
{
|
||||||
if(!$this->getDatabaseRecords()) {
|
if(!$this->getDatabaseRecords()) {
|
||||||
@ -110,19 +154,22 @@ class TrainingManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function firstRecordData(): array
|
private function firstRecordData(): stdClass
|
||||||
{
|
{
|
||||||
return [
|
$data = new stdClass();
|
||||||
'first_step' => [
|
$short_names = [
|
||||||
'complete' => 0,
|
'first_step',
|
||||||
'progress' => [
|
'second_step'
|
||||||
'current' => 0,
|
|
||||||
'need' => 0,
|
|
||||||
]
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
foreach ($short_names as $name) {
|
||||||
|
$data->$name->complete = false;
|
||||||
|
$data->$name->progress->current = 0;
|
||||||
|
$data->$name->progress->need = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
public function __get(string $name)
|
public function __get(string $name)
|
||||||
{
|
{
|
||||||
return $this->steps[$name];
|
return $this->steps[$name];
|
||||||
@ -130,11 +177,25 @@ class TrainingManager
|
|||||||
|
|
||||||
public function addPoint(string $short_name)
|
public function addPoint(string $short_name)
|
||||||
{
|
{
|
||||||
$this->$short_name->progress++;
|
$this->database_records->data->$short_name->progress->current++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function nextStep()
|
||||||
|
{
|
||||||
|
foreach ($this->database_records->data as $step) {
|
||||||
|
if($step->complete === false && $step->progress->current >= $step->progress->need) {
|
||||||
|
$step->complete = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function store()
|
public function store()
|
||||||
{
|
{
|
||||||
|
$this->nextStep();
|
||||||
|
|
||||||
|
Db::run('UPDATE user_training SET data = ? WHERE user_id = ?', [
|
||||||
|
json_encode($this->database_records->data),
|
||||||
|
$this->user_id
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
4
api/.htaccess
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<IfModule mod_rewrite.c>
|
||||||
|
RewriteEngine On
|
||||||
|
RewriteRule ^training/complete/?$ index.php?get=complete [L]
|
||||||
|
</IfModule>
|
47
api/index.php
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use DarksLight2\Training\TrainingManager;
|
||||||
|
|
||||||
|
header('Content-type: application/json');
|
||||||
|
|
||||||
|
if (!defined('GAME_VERSION')) {
|
||||||
|
require_once '../_incl_data/autoload.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = User::start();
|
||||||
|
|
||||||
|
if($input = file_get_contents("php://input")) {
|
||||||
|
$data = json_decode($input);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!empty($user->info)) {
|
||||||
|
|
||||||
|
$training = TrainingManager::getInstance($user->info['id']);
|
||||||
|
|
||||||
|
if (!isset($data->token) || !password_verify(
|
||||||
|
$training->getDatabaseRecords()->api_token . $data->time . $user->info['id'],
|
||||||
|
$data->token
|
||||||
|
)) {
|
||||||
|
http_response_code(401);
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_GET['get'])) {
|
||||||
|
switch ($_GET['get']) {
|
||||||
|
default:
|
||||||
|
http_response_code(400);
|
||||||
|
die;
|
||||||
|
case 'complete':
|
||||||
|
if ($training->{$data->short_name}->isComplete) {
|
||||||
|
http_response_code(400);
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
|
||||||
|
$training->addPoint($data->short_name);
|
||||||
|
$training->nextStep();
|
||||||
|
$training->store();
|
||||||
|
|
||||||
|
die(json_encode(['status' => 'ok']));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,7 @@
|
|||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
background: rgba(0, 0, 0, 0.5);
|
/*background: rgba(0, 0, 0, 0.5);*/
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
@ -1,3 +1,24 @@
|
|||||||
|
const request = new XMLHttpRequest();
|
||||||
|
|
||||||
|
const training_handler = () => {
|
||||||
|
request.open('POST', '/api/training/complete')
|
||||||
|
request.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
|
||||||
|
request.onreadystatechange = function() {//Call a function when the state changes.
|
||||||
|
if(request.readyState === 4 && request.status === 200) {
|
||||||
|
parent.frames['main'].location.reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
request.send(JSON.stringify({
|
||||||
|
time: training_data().time,
|
||||||
|
token: training_data().token,
|
||||||
|
short_name: training_data().short_name
|
||||||
|
}))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
let active_training = null;
|
||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
if (typeof window.CustomEvent === "function") return false;
|
if (typeof window.CustomEvent === "function") return false;
|
||||||
function CustomEvent(event, params) {
|
function CustomEvent(event, params) {
|
||||||
|
9
main.php
@ -29,11 +29,14 @@
|
|||||||
<div class="se-pre-con" id="se-pre-con"></div>
|
<div class="se-pre-con" id="se-pre-con"></div>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
|
||||||
if (!defined('GAME_VERSION')) {
|
if (!defined('GAME_VERSION')) {
|
||||||
require_once '_incl_data/autoload.php';
|
require_once '_incl_data/autoload.php';
|
||||||
}
|
}
|
||||||
|
|
||||||
use Core\{Config, Database, Db};
|
use Core\{Config, Database, Db};
|
||||||
|
use DarksLight2\Training\TrainingManager;
|
||||||
DarksLight2 marked this conversation as resolved
Outdated
lopar
commented
Нужны ли игроку технические исключения? Нужны ли **игроку** технические исключения?
DarksLight2
commented
Солгасен, тупанул Солгасен, тупанул
|
|||||||
|
|
||||||
function var_info($vars, $d = false)
|
function var_info($vars, $d = false)
|
||||||
{
|
{
|
||||||
DarksLight2 marked this conversation as resolved
Outdated
lopar
commented
На На https://src.lopar.space/new-combats.com/game/src/commit/dcc6a1337c861b9f2dfd957aeebc6e1c6d8cc85b/main.php#L59 вызывается инстанс User. Зачем вызывать ещё один на 20 строк выше?
DarksLight2
commented
Не обратил внимание) Не обратил внимание)
|
|||||||
@ -556,6 +559,12 @@ $spl = $spl['exp'];
|
|||||||
echo '<script>top.myexpLineTop27(' . $u->info['exp'] . ',' . $spl . ');' . $tjs . 'top.ctest("' . $u->info['city'] . '");top.sd4key="' . $u->info['nextAct'] . '"; var battle = ' . (0 + $u->info['battle']) . '; top.hic();</script></body>
|
echo '<script>top.myexpLineTop27(' . $u->info['exp'] . ',' . $spl . ');' . $tjs . 'top.ctest("' . $u->info['city'] . '");top.sd4key="' . $u->info['nextAct'] . '"; var battle = ' . (0 + $u->info['battle']) . '; top.hic();</script></body>
|
||||||
</html>';
|
</html>';
|
||||||
|
|
||||||
|
$training_manager = TrainingManager::getInstance();
|
||||||
|
|
||||||
|
if($u->room['file']=='cp1') {
|
||||||
|
$training_manager->first_step->render();
|
||||||
|
$training_manager->second_step->render();
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
<!--<script src="https://cdnjs.cloudflare.com/ajax/libs/modernizr/2.8.2/modernizr.js"></script>-->
|
<!--<script src="https://cdnjs.cloudflare.com/ajax/libs/modernizr/2.8.2/modernizr.js"></script>-->
|
||||||
<script>
|
<script>
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
<?
|
<?
|
||||||
|
|
||||||
use DarksLight2\Training\TrainingManager;
|
|
||||||
|
|
||||||
if(!defined('GAME'))
|
if(!defined('GAME'))
|
||||||
{
|
{
|
||||||
DarksLight2 marked this conversation as resolved
Outdated
lopar
commented
Убирая где-то Убирая где-то `__config.php` и `__db_connect.php` надо вместо них вызывать `Config::init()` и `Database::init()`. Первое подтягивает настройки, второе подтягивает функции `mysql_`.
DarksLight2
commented
Я же убирал галочку ( Я же убирал галочку (
|
|||||||
die();
|
die();
|
||||||
@ -11,9 +9,6 @@ require_once('/home/newcom1/public_html/_incl_data/class/__db_connect.php');
|
|||||||
|
|
||||||
if($u->room['file']=='cp1') {
|
if($u->room['file']=='cp1') {
|
||||||
|
|
||||||
$training_manager = TrainingManager::getInstance();
|
|
||||||
$training_manager->first_step->render();
|
|
||||||
|
|
||||||
if(date("H")>=8 && date("H")<=23) {
|
if(date("H")>=8 && date("H")<=23) {
|
||||||
$now = 'day';
|
$now = 'day';
|
||||||
$tattack = '<a style="color:#D8D8D8" style="cursor:pointer" onclick="top.useMagic(\'Нападение на персонажа\',\'night_atack\',\'pal_button8.gif\',1,\'main.php?nightatack=1\');">Напасть на игрока</a> ';
|
$tattack = '<a style="color:#D8D8D8" style="cursor:pointer" onclick="top.useMagic(\'Нападение на персонажа\',\'night_atack\',\'pal_button8.gif\',1,\'main.php?nightatack=1\');">Напасть на игрока</a> ';
|
||||||
|
@ -1,23 +1,26 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use DarksLight2\Training\TrainingManager;
|
/**
|
||||||
|
* @var string $token
|
||||||
|
* @var int $time
|
||||||
|
* @var string $button_text
|
||||||
|
* @var object $step
|
||||||
|
*/
|
||||||
|
|
||||||
$short_name = 'first_step';
|
$short_name = 'first_step';
|
||||||
DarksLight2 marked this conversation as resolved
Outdated
lopar
commented
`basename($_SERVER['PHP_SELF'], '.php')` не?
|
|||||||
|
|
||||||
$manager = TrainingManager::getInstance();
|
require 'step.php';
|
||||||
$step = $manager->$short_name;
|
|
||||||
$button_text = 'Продолжить';
|
|
||||||
if(!$manager) {
|
|
||||||
$button_text = '';
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
|
|
||||||
|
?>
|
||||||
<script>
|
<script>
|
||||||
const training_data = () => {
|
const training_data = () => {
|
||||||
return {
|
return {
|
||||||
content: `<?=$step->message?>`,
|
content: `<?=$step->message?>`,
|
||||||
title: `<?=$step->title?>`,
|
title: `<?=$step->title?>`,
|
||||||
button_text: `<?=$button_text?>`
|
button_text: `<?=$button_text?>`,
|
||||||
|
time: <?=$time?>,
|
||||||
|
token: '<?=$token?>',
|
||||||
|
short_name: '<?=$short_name?>',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
31
modules_data/steps/second_step.php
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string $token
|
||||||
|
* @var int $time
|
||||||
|
* @var string $button_text
|
||||||
|
* @var object $step
|
||||||
|
*/
|
||||||
|
|
||||||
|
$short_name = 'second_step';
|
||||||
DarksLight2 marked this conversation as resolved
Outdated
lopar
commented
`basename($_SERVER['PHP_SELF'], '.php')` не?
DarksLight2
commented
заменю заменю
|
|||||||
|
|
||||||
|
require 'step.php';
|
||||||
|
|
||||||
|
?>
|
||||||
|
<script>
|
||||||
|
const training_data = () => {
|
||||||
|
return {
|
||||||
|
content: `<?=$step->message?>`,
|
||||||
|
title: `<?=$step->title?>`,
|
||||||
|
button_text: `<?=$button_text?>`,
|
||||||
|
time: <?=$time?>,
|
||||||
|
token: '<?=$token?>',
|
||||||
|
short_name: '<?=$short_name?>',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script src="/js/training/modal.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
modal.show()
|
||||||
|
</script>
|
16
modules_data/steps/step.php
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
DarksLight2 marked this conversation as resolved
lopar
commented
Точно классы вызовутся без загрузчика? Точно классы вызовутся без загрузчика?
DarksLight2
commented
этот файл инклудится, чтобы не дублировать код вынес в отдельный файл этот файл инклудится, чтобы не дублировать код вынес в отдельный файл
|
|||||||
|
/**
|
||||||
DarksLight2 marked this conversation as resolved
Outdated
lopar
commented
Не надо такое прописывать в отдельных файлах, чтобы потом общие настройки игнорировались и перезаписывались. Не надо такое прописывать в отдельных файлах, чтобы потом общие настройки игнорировались и перезаписывались.
DarksLight2
commented
Я для себя ставил и забыл убрать( Я для себя ставил и забыл убрать(
|
|||||||
|
* @var string $short_name
|
||||||
|
*/
|
||||||
|
|
||||||
|
$user = User::start();
|
||||||
|
|
||||||
|
use DarksLight2\Training\TrainingManager;
|
||||||
|
|
||||||
|
$manager = TrainingManager::getInstance();
|
||||||
|
$step = $manager->$short_name;
|
||||||
|
$button_text = 'Продолжить';
|
||||||
|
$time = time();
|
||||||
|
|
||||||
|
$token = password_hash($manager->getDatabaseRecords()->api_token . $time . $user->info['id'], PASSWORD_DEFAULT);
|
Тест - так и задумано?
это нужно с Евгением говорить чтобы написал тексты, но в целом да