30

» WarCraft 3 / Связанные юниты

Smeto, смотри, на хэндл юнита A вещаем хэндл юнита B. На хэндл юнита B вешаем хэндл юнита A.
При смерти одного из них убиваем второго.
Ты же на хэндл юнита A вешаеш хэндл юнита A. Зачем? Его же можно получить через GetUnitHandle().
Другой момент, что таким образом к одному юниту можно привязать только одного юнита. Для более сложных взаимодействий и цепочек связей придётся что-то похитрее городить.

Делаем триггер на него вешаем бойцов и смерть бойцов по хэндлу триггера.
Один из них умер - убиваем второго (или двоих). Ну, и не забываем очищать всё. Дабы утечек небыло.
Профит
Не вижу смысла в динамических триггерах, ибо всёравно с хэндлами возиться, а задача спокойно и с одним триггером решается.
30

» WarCraft 3 / Связанные юниты

Smeto, зачем на юнита сохранять хэндл этого же юнита? Да и условие можно убрать, а поиск второй половинки засунуть в триггер смерти юнита.
30

» God's word: The True Way / Требуются тестеры

ну если бы я пилил рпг
Можно и тупо текстовое рпг замутить, я даже примитивный движок набросал, который можно форкнуть и допилить под нужды)
30

» WarCraft 3 / Связанные юниты

...которая медленнее
Получить однно значение из ХТ медленнее перебора массива непонятной длины?
30

» WarCraft 3 / ZinC: Rectangle

konvan5, добавил distanceSquaredInnerXY, которая возвращает положительное значение если точка внутри прямоугольника и отрицательное если снаружи. Теперь через тот же IsUnitInRangeXY можно легко посчитать, находится ли юнит полностью в прямоугольнике.
30

» WarCraft 3 / Заказы на ландшафт

Заказ на работу

Карта для демонстрации заклинаний 1.26

Идея в том что слева направо бегут юниты и умирают интересным способом, а по центру стоит герой и кастует в них всякое.
Размер карты: хватит и 36x36, главное чтоб переход в неиграбельную темноту не смотрелся коряво.
Тип ландшафта: на выбор автора
Климат/Природа: на выбор автора
Что вы хотите увидеть на карте дополнительно: нельзя создавать новые объекты (юниты, декорации, и т.д. ), только менять характеристики уже существующим. Обязательно долженствуют быть несколько стандартных клифов, глубокая и мелкая вода.
Тематика секретных фишок карты: на выбор автора
Стиль: на выбор автора
Разметка местности блокираторами пути и видимости: на выбор автора
Необходимость импорта: только источники света и прочую не весящую мелочь.
Награда, если готовы поддержать автора материально: 100 гривен (при желании можно повысить). К сожалению из-за плохих погодных условий не на каждый банк смогу перевести.

Карту желательно опубликовать на xgm и заполнить лоадскрин указанием своего авторства.
30

» WarCraft 3 / ZinC: Rectangle

konvan5, если по простому, детектится наложение круга на прямоугольник. Визуализацию можно в WebDemo глянуть.
Иначе узкий квадрат не будет задевать жирных юнитов. Но математика там не сложная, если нужно могу дописать.
Классно, а теперь в 3д с поверхностями)
Когда завезут нативку по получению центра модели юнита, тогда сделаю 👽
30

» WarCraft 3 / ZinC: Rectangle

Нормально запарились над мелочами :D
Да не, лажа какая-то, в WebDemo событие touchmove не обрабатывается и соответственно с мобилок демку не пощупать.
30

» Администрация XGM / Пуш уведомления

Там нужен composer, который политически неравнодушен.
"require": {
    "php": ">=7.3",
    "ext-curl": "*",
    "ext-json": "*",
    "ext-mbstring": "*",
    "ext-openssl": "*",
    "guzzlehttp/guzzle": "^7.0.1|^6.2",
    "web-token/jwt-signature": "^2.0|^3.0.2",
    "web-token/jwt-key-mgmt": "^2.0|^3.0.2",
    "web-token/jwt-signature-algorithm-ecdsa": "^2.0|^3.0.2",
    "web-token/jwt-util-ecc": "^2.0|^3.0.2",
    "spomky-labs/base64url": "^2.0"
  },

Я кстати костылил такое же вообще без всяких зависимостей.
раскрыть
<?php
declare(strict_types=1);

namespace Send;

use CurlHandle;
use Exception;
use JetBrains\PhpStorm\ArrayShape;
use Util\Response;

class Comet {
	private static CurlHandle $ch;
	private static string     $project_id = 'my-project-id';
	private static ?string    $token      = null;


	/**
	 * @param array  $data
	 * @param array  $counter
	 * @param array  $notification
	 * @param string $route
	 * @return array[]
	 */
	#[ArrayShape(['message' => 'array'])]
	private static function message(
		array  $data,
		array  $counter,
		array  $notification = [],
		string $route = ''
	): array {
		$data += [
			//'click_action'   => 'FLUTTER_NOTIFICATION_CLICK',
			'data_timestamp' => (string)time()
		];

		if (count($counter) > 0) {
			$data['data_counter'] = $counter;
		}

		if (mb_strlen($route) > 0) {
			$data['data_route'] = $route;
		}

		foreach ($data as $k => $v) {
			if (is_string($v)) {
				continue;
			} elseif (is_array($v)) {
				$data[$k] = json_encode($v);
			} else {
				settype($data[$k], 'string');
			}
		}

		/**
		 * @see https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages
		 */
		$message = [
			'data' => $data,
		];

		if (count($counter) > 0) {
			$message += ['apns' => ['payload' => ['aps' => [
				'mutable-content' => 1,
				'badge'           => $counter['summary'],
			]]]];
		}

		if (count($notification) > 0) {
			$message = array_merge_recursive($message, [
				'notification'      => [
					'title' => $notification[0],
					'body'  => $notification[1] ?? '',
				],
				'apns'              => [
					'payload' => [
						'aps' => [
							'sound' => 'default'
						]
					]
				],
				'android'           => [
					'priority'     => 'HIGH',
					'notification' => [
						'sound' => 'default'
					]
				]
			]);
		}

		return $message;
	}

	/**
	 * @param CometType $type
	 * @param int|null  $user_id
	 * @param array     $data
	 * @param array     $notification
	 * @param string    $route
	 * @return array
	 * @throws Exception
	 */
	public static function send(
		CometType $type,
		?int      $user_id,
		array     $data,
		array     $notification = [],
		string    $route = ''
	): array {
		[$list, $counter] = DB::user_token_list($user_id)->execute();

		$tokens = [];
		foreach ($list as $v) {
			$tokens[] = $v['token'];
		}

		if (count($tokens) == 0) {
			Response::bad_request();
		}

		$access_token = self::$token ?? self::token();

		if ($access_token == null) {
			Response::bad_request();
		}

		$message = self::message(
			data:         $data + ['type' => $type->name],
			counter:      count($counter) > 0 ? $counter[0] : [],
			notification: $notification,
			route:        $route
		);

		curl_setopt_array(self::$ch, [
			CURLOPT_URL        => 'https://fcm.googleapis.com/v1/projects/' . self::$project_id . '/messages:send',
			CURLOPT_HTTPHEADER => [
				'Connection: close',
				'Content-Type: application/json',
				"Authorization: Bearer $access_token",
			],
		]);

		$unset   = [];
		$success = [];

		$send = function (int $attempt) use (&$send, &$tokens, &$message, &$unset, &$success) {
			while (count($tokens) > 0) {
				$token = array_shift($tokens);

				$message['token'] = $token;
				curl_setopt(self::$ch, CURLOPT_POSTFIELDS, json_encode(['message' => $message]));

				$status   = curl_getinfo(self::$ch, CURLINFO_HTTP_CODE);
				$response = curl_exec(self::$ch);

				switch (json_decode($response, true)['error']['status'] ?? null) {
					case 'UNAUTHENTICATED':
					case 'NOT_FOUND':
						$unset[] = $token;
						break;
					case 'INTERNAL':
						if ($attempt <= 5) {
							$tokens[] = $token;
							set_time_limit(10);
							usleep($attempt * 1050000);
							$send($attempt + 1);
							break 2;
						}
						break;
					case 'INVALID_ARGUMENT':
						if (mb_strpos($response, 'message.token') > 0) {
							echo "--------- invalid token\n\n";
						} else {
							var_dump($response);
						}
						break;
					default:
						if ($status == 200) {
							$success[] = [$response, $message];
						} else {
							var_dump($response);
						}
				}

			}
		};

		$send(1);

		curl_close(self::$ch);

		if (count($unset) > 0) {
			DB::user_token_unset(implode(',', $unset))->execute();
		}

		return $success;
	}

	private static function token(): ?string {
		$time = time();
		$aud  = 'https://oauth2.googleapis.com/token';

		$JWT = base64_encode(json_encode(['alg' => 'RS256', 'typ' => 'JWT']))
		       . '.' .
		       base64_encode(json_encode([
			                                 'iss'   => 'firebase-adminsdk-9p1bi@' . self::$project_id . '.iam.gserviceaccount.com',
			                                 'scope' => 'https://www.googleapis.com/auth/firebase.messaging',
			                                 'aud'   => $aud,
			                                 'iat'   => $time,
			                                 'exp'   => $time + 3600
		                                 ]));

		$private_key = <<<EOT
-----BEGIN PRIVATE KEY-----
-----END PRIVATE KEY-----
		
EOT;
		$signature   = '';
		openssl_sign($JWT, $signature, $private_key, OPENSSL_ALGO_SHA256);

		curl_setopt_array(self::$ch = curl_init(), [
			CURLOPT_URL            => $aud,
			CURLOPT_PORT           => 443,
			CURLOPT_POST           => true,
			CURLOPT_RETURNTRANSFER => true,
			CURLOPT_HTTP_VERSION   => CURL_HTTP_VERSION_1_0,
			CURLOPT_HTTPHEADER     => ['Connection: close'],
			CURLOPT_POSTFIELDS     => [
				'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
				'assertion'  => $JWT . '.' . base64_encode($signature),
			],
		]);

		$call = function (int $attempt) use (&$call): ?string {
			$response = json_decode(curl_exec(self::$ch), true);
			$status   = curl_getinfo(self::$ch, CURLINFO_HTTP_CODE);

			if ($status != 200 || !array_key_exists('access_token', $response)) {
				if ($attempt > 5) {
					curl_close(self::$ch);
					return null;
				}
				set_time_limit(10);
				usleep($attempt * 1050000);
				return $call($attempt + 1);
			}

			return self::$token = $response['access_token'];
		};

		return $call(1);
	}

}
30

» Администрация XGM / О стороннем контенте

Ссылки должны быть в формате результатов выдачи поисковика
А таким образом можно ссылки давать?
30

» WarCraft 3 / Luacraft - декларации типов для Typescript to Lua

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

» WarCraft 3 / Luacraft - декларации типов для Typescript to Lua

Потом можно будет писать код на классах
Зачем? Это же будет гигансткая обёртка, которая будет предоставлять посредственный функционал.
30

» WarCraft 3 / JNGP: Rebuild от PT153

Сбылась мечта идиота спустя 10 лет - редактор на английском языке.
30

» WarCraft 3 / Зависимость уровня способности у юнита

EugeAl, Насколько я помню, должно быть событие Игрок призывает юнита, оно бы упростило задачу.
лучайное, от 1 до 1000 например
С шансом 1/1000 два кастера всё сломают.
30

» WarCraft 3 / Зависимость уровня способности у юнита

EugeAl, два кастера рядом всё сломают.

Я делаю это чтоб не делать дополнительные способности под каждого Волка призываемого способностью (Дух волка).
Думаю так будет гораздо проще.
30

» Unryze Jass API / UjAPI

и пока скрипт не скачается игрок будет лагать)))
Нехай асинхронно качает.
30

» WarCraft 3 / Как сделать AOE способность?

Ребята не подскажите кто не будь как можно восстановить триггеры карты?
Почему они сломались и не отдельным вопросом?
Выбрать лучший ответ тоже не помешало бы.
30

» Unryze Jass API / UjAPI

Ev3nt, require для lua реализован или самому сборкой заниматься?
30

» Unryze Jass API / UjAPI

Unryze, тоесть сейчас возможна паралельная работа jass и lua? Общение между ними не особо и нужно.~ScorpioT1000:
опенсорс - это когда как раз не присваивают, а делятся форками
Но история знает примеры с нескучными обоями.