19

» WarCraft 3 / Синхронизация данных

Всё же, информация о том, что игра может отказаться слать команду из-за переполнения буфера оказалась ложной. Если это происходит, то игра сначала сбрасывает буфер хосту и затем снова проверяет, поместится ли команда и только лишь в противном случае отбрасывает её.
IDA HexRays псевдокод функции отправки команды
void __fastcall NetSendCommandStore(CDataStore *stream, int SessionId)
{
  CNetData *NetData; // esi
  CPlayerWar3 *player; // eax
  DWORD length; // [esp+Ch] [ebp-Ch] MAPDST BYREF
  void *buffer; // [esp+10h] [ebp-8h] BYREF

  NetData = (CNetData *)*((_DWORD *)GetWc3Prop(PROP_SYNDATA)[4] + SYNDATA_NETDATA);
  if ( SessionId == NetData->ActiveSessionId_
    && *(_DWORD *)&NetData->Sessions.buffer_field1EC[0x304 * SessionId + 0x7C] >= GAME_STATE_LOADING )
  {
    stream->vtable->GetValues(stream, &buffer, &length, 0);
    if ( length )
    {
      if ( SessionId
        || !g_GameWar3
        || (player = CGameWar3::GetPlayer(g_GameWar3, g_GameWar3->LocalPlayerId),
            !CPlayerWar3::IsActionLimitReached(player, *(_BYTE *)buffer)) )
      {
        if ( length + NetData->ActionsStream.Length - NetData->ActionsStreamOverhead >= 1024 )
          CNetData::SendCommands(NetData); // после этого вызова буфер очищается
        if ( length + NetData->ActionsStream.Length - NetData->ActionsStreamOverhead >= 1024 )
          debug_log("NetSendCommandStore: rejected, %u bytes\n", length);
        else
          Stream::Write(&NetData->ActionsStream, buffer, length);
      }
    }
  }
}
19

» WarCraft 3 / Пропадают названия диалогов

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

» WarCraft 3 / Открытая виртуальная машина

У меня были мысли о создании проэкта для совместного реверсинга варкрафта, как у майнкрафта есть MCP. Только нужно придумать как это всё оформить.
19

» WarCraft 3 / Открытая виртуальная машина

Те, кто уже успел скачать, лучше перекачайте, так как кнопка "скачать" ссылалась на архив с версией без лимита операций (JassAcceleratorLimitless.zip), которая может привести к десинхронизации при игре в картах, в которых поток выполнения jass-скрипта обрывается из-за, например, бесконечных циклов. Разработчик мог не заметить ошибки, а вас выбросит из игры.
19

» WarCraft 3 / Работа с нативными функциями

IceFog, Пожалуйста выложи свой JassApi,dll
Исправил. Теперь кнопка скачать ссылается на правильный архив.
Похоже, что главным файлом ресурса считается идущий последним в списке, а не первым.
19

» WarCraft 3 / Просмотр состояния виртуальной машины JASS

без ошибки, просто фризит и вылетает
В таком случае, даже с поддержкой рефорджа она всё равно не помогла бы, так как процесс варкрафта уже будет убит ко времени запуска программы и никаких данных собрать не выйдет.
Здесь лучше подошел бы какой-нибудь логер вызовов нативок.
19

» WarCraft 3 / Работа с нативными функциями

Строки ведь не уничтожаются до конца игры
В этой версии виртуальной машины работа со строками идет таким образом, что они не утекают.
19

» WarCraft 3 / Внутреннее устройство виртуальной машины

Если убрать проверку на аргументы, то игра начнет автоматически обнулять переменные и тогда перестанут утекать слоты таблицы хэндлов.
Также можно уничтожать объекты на которые ссылались освобожденные хэндлы и забыть об ошибках выделения памяти из-за мусорных точек, групп и прочего.
Но в таком случае, мод должен будет присутствовать на всех клиентах, а иначе десинхронизация.
19

» WarCraft 3 / Помогите с синхронизацией

У функции SyncStoredString реализована отправка команды синхронизации, но не её прием.
Более того, все команды, что будут идти сразу за ней в одном буфере действий игрока проигнорируются.
Вызов следующего кода приведет к тому, что юнит визуально будет выделен, но на команды реагировать не будет.
call SyncStoredString(Cache, Key1, Key2)
call SelectUnit(u, True)
19

» WarCraft 3 / Почему вызов триггера является синхронным действием?

Принятый ответ
За последовательное выполнение всех действий триггера и за выход из сна отвечает объект CTriggerExecution, который является агентом, а их нельзя создавать локально.
19

» WarCraft 3 / Что предпочтительней и почему Lua или Jass?

Первая карта (benchmark.w3m) содержит исходники скрипта.
Вторая карта (benchmark-packed.w3m) уже укомплектована DLL с нативками и готова к запуску.
Загруженные файлы
19

» WarCraft 3 / Что предпочтительней и почему Lua или Jass?

Unryze
Длина переменной не влияет на скорость никак - это очередной тупой миф
Написал для теста код, что упорядочивает массив используя сортировку пузырьком.
функция сортировки
function s__NormalArray_sort takes nothing returns nothing
local boolean swapped
local integer temp
local integer i

	loop
		set swapped = false
		set i = 0

		loop
			exitwhen not (i < JASS_MAX_ARRAY_SIZE-1)

			if items[i] > items[i+1] then
				set temp = items[i]
				set items[i] = items[i+1]
				set items[i+1] = temp
				set swapped = true
			endif

			set i = i + 1
		endloop

		exitwhen not swapped
	endloop
	
endfunction

Результаты теста

Имена переменных Затраченное время
Без изменений 90704 мс (1 минута 30 секунд)
Длина 1 символ 84484 мс (1 минута 24 секунд)
Длина 85 символов 387219 мс (6 минут 27 секунд)
Длина 340 символов 1235703 мс (20 минут 35 секунд)

Исходники JASS скрипта

Caller
library Caller initializer init {

     #include "cj_types_priv.j"

    private force dummy_force

    void CallFunction(code f) {
        ForForce(dummy_force, f)
    }

    private void init() {
        dummy_force = CreateForce()
        ForceAddPlayer(dummy_force, Player(0))
    }

}
Benchmark
native GetTickCount takes nothing returns integer
native SetOperationLimitEnabled takes boolean state returns nothing
native IsOperationLimitEnabled takes nothing returns boolean

library benchmark initializer init uses Caller {

    #include "cj_types_priv.j"

    define ITEMS_COUNT = JASS_MAX_ARRAY_SIZE
    
    define MAKE_SORTABLE_ARRAY(TYPE_NAME, items, swapped, temp, i) = {
        integer items[]
    
        struct TYPE_NAME {
        
            static void fill() {
                for (int i = 0; i < ITEMS_COUNT; i++) {
                    items[i] = ITEMS_COUNT - 1 - i
                }
            }
            
            static void sort() {
                bool swapped
                int temp
                int i;
                
                loop {
                    swapped = false
                    
                    for (i = 0; i < ITEMS_COUNT-1; i++) {
                        if items[i] > items[i+1] {
                            temp = items[i]
                            items[i] = items[i+1]
                            items[i+1] = temp
                            swapped = true
                        }
                    }
                    
                    exitwhen not swapped
                }
                
                BJDebugMsg("Sorting finished.")
            }
            
            static bool check() {
                for (int i = 0; i < ITEMS_COUNT-1; i++) {
                    if items[i] > items[i+1] {
                        return false
                    }
                }
                
                for (int i = 0; i < ITEMS_COUNT; i++) {
                    if items[i] != i {
                        return false
                    }
                }
                
                return true
            }
            
            static void benchmark() {
                fill()
                
                int start_time = GetTickCount()
                
                CallFunction(function thistype.sort)
                
                int end_time = GetTickCount()
                int difference = end_time - start_time
                
                if !check() {
                    BJDebugMsg("Sorting failed.")
                }
                else {
                    BJDebugMsg("Time elapsed: " + I2S(difference) + " ms.")
                }
            }
        }
    }
    
    MAKE_SORTABLE_ARRAY(FastArray, a, b, c, d)
    MAKE_SORTABLE_ARRAY(NormalArray, items, swapped, temp, i)
    MAKE_SORTABLE_ARRAY(SlowArray,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc,ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd)
    MAKE_SORTABLE_ARRAY(VerySlowArray,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc,dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd)
    
    void start() {
        bool old_state = IsOperationLimitEnabled()
        SetOperationLimitEnabled(false)
        
        CallFunction(function FastArray.benchmark)
        CallFunction(function NormalArray.benchmark)
        CallFunction(function SlowArray.benchmark)
        CallFunction(function VerySlowArray.benchmark)
        
        SetOperationLimitEnabled(old_state)
    }
    
    void init() {
        trigger t = CreateTrigger()
        TriggerAddAction(t, function start)
        TriggerRegisterPlayerChatEvent(t, Player(0), "-start", true)
    }

}

Другие языки

На Pascal'е сортировка заняла 85 мс, что почти в тысячу раз быстрее.
А при использовании статических массивов время снизилось до 72 мс.
Тот же результат выдала и моя asm реализация независимо от типа массива.
pascal
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
	Windows,
	Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;

type

	{ TForm1 }

	TForm1 = class(TForm)
		StartButton: TButton;
		Log: TMemo;
		procedure StartButtonClick(Sender: TObject);
	private

	public

	end;

    //{$define STATIC_ARRAY}

const
	TEST_ARRAY_SIZE = 8192;

type
	TIntegerArray = array {$ifdef STATIC_ARRAY}[0..TEST_ARRAY_SIZE-1]{$endif} of Integer;
	TSortFunction = procedure (var Items: TIntegerArray);

var
	Form1: TForm1;

implementation

{$R *.lfm}

procedure FillArray({$ifdef STATIC_ARRAY}out{$endif} Items: TIntegerArray);
var
	i: Integer;
begin
	for i:= 0 to High(Items) do begin
		Items[i]:= High(Items) - i;
	end;
end;

procedure BubbleSort({$ifdef STATIC_ARRAY}var{$endif} Items: TIntegerArray);
var
	i: Integer;
	Temp: Integer;
	Swapped: Boolean;
begin
	repeat
		Swapped:= False;

		for i:= 0 to High(Items) - 1 do begin
			if Items[i] > Items[i+1] then begin
				Temp:= Items[i];
				Items[i]:= Items[i+1];
				Items[i+1]:= Temp;

				Swapped:= True;
			end;
		end;

	until not Swapped;
end;

procedure BubbleSortASM(Items: PInteger; Count: Integer); cdecl;
begin
	asm
		pushad

		mov edx, Items
		mov ebx, Count
		dec ebx

		@repeat:
			mov eax, False

			xor ecx, ecx
			@loop:
				lea ebp, [edx+ecx*4]
				mov esi, [ebp]
				mov edi, [ebp+4]

				cmp esi, edi
				jle @skip
					mov [ebp], edi
					mov [ebp+4], esi
					mov eax, True

				@skip:

				inc ecx
				cmp ecx, ebx
				jl @loop

			test eax, eax
			jnz @repeat

		popad
	end;
end;

function IsArraySorted({$ifdef STATIC_ARRAY}const{$endif} Items: TIntegerArray): Boolean;
var
	i: Integer;
begin
	Result:= True;

	for i:= 0 to High(Items) - 1 do begin
		if Items[i] > Items[i+1] then
			Result:= False;
	end;

	for i:= 0 to High(Items) do begin
		if Items[i] <> i then
			Result:= False;
	end;
end;

procedure StartTest(TestFunction: TSortFunction);
var
	Items: TIntegerArray = nil;
	Frequency: Qword;
	StartTime, EndTime, ElapsedTime: Qword;
begin
	QueryPerformanceFrequency(@Frequency);

	{$ifndef STATIC_ARRAY}SetLength(Items, TEST_ARRAY_SIZE);{$endif}
	FillArray(Items);

	QueryPerformanceCounter(@StartTime);
	TestFunction(Items);
	QueryPerformanceCounter(@EndTime);

	ElapsedTime:= EndTime - StartTime;

	if IsArraySorted(Items) then
		Form1.Log.Lines.Add('Time elapsed: %d ms.', [ElapsedTime div (Frequency div 1000)])
	else
		Form1.Log.Lines.Add('Sorting failed.');
end;

procedure BubbleSortBenchmark(var Items: TIntegerArray);
begin
	BubbleSort(Items);
end;

procedure BubbleSortASMBenchmark(var Items: TIntegerArray);
begin
	BubbleSortASM(@Items[0], Length(Items));
end;

{ TForm1 }

procedure TForm1.StartButtonClick(Sender: TObject);
begin
	StartTest(@BubbleSortBenchmark);
	StartTest(@BubbleSortASMBenchmark);
end;

end.
19

» WarCraft 3 / Сценарий на любом языке

Ты собираешься встроить в карту mix-архив?
Разве в этом есть какой-либо толк?
Как бы то ни было, у моей системы не должно быть проблем с их загрузкой.
19

» WarCraft 3 / Сценарий на любом языке

Всё возможно уже сейчас, в своей библиотеке, пользователь может и виртуальную машину python'а загрузить, и игру на Unity запустить.
19

» WarCraft 3 / MapHack для реплея

не работает кнопка ESC
Теперь хоткей "Ctrl Escape", исправил описание.
отключить Окно Смерти Курьеров
добавить CreateLeaderboard
Локальное (не)создание агента может привести к десинку, лучше заблокировать нативку, отвечающую за показ таблицы.
19

» WarCraft 3 / MapHack для реплея

SJ Cyber Droeed, да, такая возможность не помешает, если появятся время и желание - сделаю, а пока советую поискать обычные мапхаки, которые умеют показывать кд предметов и не крашатся в реплее.
19

» WarCraft 3 / Сценарий на любом языке

WarGoose, библиотеки и так исполняются при загрузке, так что нет нужды в дополнительных действиях.
19

» WarCraft 3 / Сценарий на любом языке

Не могли бы вы объяснить?
В архиве, прикрепленном к этому ресурсу, изначально находится набор библиотек, которые необходимы для работы системы, так что не стоит их удалять.
Из предоставленных же мною исходников сценария, компилируется файл "Example.dll", который и был использован в карте-примере.
19

» WarCraft 3 / Telemetry.txt

Принятый ответ
В этом файле хранятся хэши строковых команд, используемых для активации читов.
19

» WarCraft 3 / Выделение памяти в хеш-таблице

Для доступа к ячейке хэштаблицы jass'а нужно пройти через 3 словаря.
Ключ для первого - номер хэштаблицы, для остальных двух - parentKey и childKey.
Игра использует собственные коллекции.
Вот как выглядит поиск в их словаре:
code
type
	generic TSHashTable<TKey, TValue, TKeyManager> = object
	public type
		PValue = ^TValue;
		TItems = specialize TSLinkedList<TValue>;
		PItems = ^TItems;
		TPages = specialize TSGrowableArray<TItems>;
	public
		vtable: Pointer;
		Items: TItems;
		Counter: Dword;
		Pages: TPages;
		HashMask: Dword;
	end;

function TSHashTable.Find(const AKey: TKey): PValue;
var
	Hash: Dword;
	Index: Integer;
	Page: PItems;
	Item: PValue;
begin
	Result:= nil;

	if HashMask = Dword(-1) then exit;
	
	Hash:= TKeyManager.GetKeyHash(AKey);
	Index:= Hash and HashMask;
	Page:= Pages.ItemPointers[Index];

	for Item in Page do begin
		if (Item^.HashKeyData.Hash = Hash) and
			TKeyManager.IsKeysEqual(Item^.HashKeyData.Key, AKey)
		then begin
			Result:= Item;
			break;
		end;
	end;
end;
19

» WarCraft 3 / Опять утечка, может ли утекать переменная типа строка?

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