Форум PSCD.ru

Игровые приставки и Эмуляция => Ромхакинг и программирование => Уроки / Документация => Тема начата: TTEMMA от 07 ноября 2014, 18:29

Название: Учимся "переводить" игры на GameCube
Отправлено: TTEMMA от 07 ноября 2014, 18:29
Введение
Всем привет.
В данной теме мы обсудим как делать перевод на GameCube, разберём одну игру, на отличный результат не претендуем, хотя бы попробуем научиться работать с файлами GC.
Игра для опытов - Spawn Armageddon (https://ru.wikipedia.org/wiki/Spawn:_Armageddon).
P.S. Данная тема будет пополняться по мере взлома игры.

Так с, для начала нам нужен софт:

На счёт первого, нам понадобится TPL Convert, лучше с генератором конфигов от DND1, чтобы самим не писать.
Так же для удобности можно установить CTools. Не уверен, что нам может понадобиться программа для работы с TPL, т.к. ещё не знаю есть ли TPL в той игре, которую будем разбирать.
 
На счёт второго, есть 2 программы для работы с образами GC(GameCube), мы будем пользоваться GameCube Rebuilder, т.к. он умеет пересобирать образы.
 
На счёт четвёртого, я использую HxD, но подойдёт любой.
 
На счёт пятого, я использую CrystalTile2, если у вас нет привязанности к другому тайловому редактору, то пользуйтесь им.
 
И на счёт шестого, данный пункт не обязателен, но в процессе разбора игры мы будем писать программы для распаковки и т.п.
P.S. На код не ругайтесь, учусь, как ни как.
 
TPL Convert (http://shedevr.org.ru/zelda64rus/tools/TPL_convert_(ConfiGen_by_dnd1).rar), CTools (http://www.chadsoft.co.uk/wiicoder/), GameCube Rebuilder (http://shedevr.org.ru/zelda64rus/tools/gcr_1.0.zip) и CrystalTile2 (http://shedevr.org.ru/zelda64rus/tools/CrystalTile2_2010_09-06.zip) можно загрузить на сайте замечательного человека Anton : Zelda64Rus (http://shedevr.org.ru/zelda64rus/downloads.html#romhacking_gc)
 
Ну что ж, приступим.
 
ЧАСТЬ 1 - Распаковка и осмотр файлов
 
Спойлер
Для начала открываем наш GCM(GameCube Rebuilder) и видим данное окно:
(http://s7.hostingkartinok.com/uploads/images/2014/11/8e82359d9fb31dd15fa5e696b2035b04.jpg)
 
Немного расскажу о функциях:
Root->Open    - Открывает Root дирректорию распакованого образа(нужно для пересборки)
Root->Save    - Выбор дирректории и имя будущего образа
Root->Close    - Закрывает открытую Root дирректорию
Root->Rebuild    - Собирает новый образ
Root->Exit    - Выход из программы
Image->Open    - Открывает образ
Image->Close   - Закрывает открытый образ
Image->Wipe garbage   - Удаляет мусор в образе
Image->Exit   - Выход из программы
Options->Modify System Files   - Наверняка активация модификации системный файлов(?)
Options->Do not use 'game.toc'   - Походу, при активации отключает использование таблицы TOC(?)
Help->About   - Об авторе
 
Узнав, для чего какая функция, откроем образ:
Клацаем  Image->Open  
Если у вас расширение у образа ISO, то просто ищем ваш образ и открываем его в программе, но если у вас расширение GCM, то меняем аттрибут GameCube ISO(*.iso) на GameCube Image File(*.gcm)
(http://s7.hostingkartinok.com/uploads/images/2014/11/7d964676a367ed32afffd683352adb9b.png)
 
После открытия образа видим данное окно(Не думаю, что файлы сильно будут отличаться от PAL версии):
(http://s7.hostingkartinok.com/uploads/images/2014/11/26c85cfb5cb2fff3bc1489229a49b110.png)
 
Жмём правой кнопкой на  "root"  в таблице файлов и жмём Export, выбираем куда сохранить папку "root" и ждём конца распаковки, по окончанию распаковки появится сообщение "Done". После этого можем приступать к осмотру файлов.
 
 
Так, файлы распакованы, HEX редактор и Тайловый редактор готов, можем приступать.
Открываем папку "root"(предварительно перейдя в ту папку, куда вы извлекли файлы образа).
Видим такие файлы:
(http://s7.hostingkartinok.com/uploads/images/2014/11/0b02637f0969466ade6266efe6a1d8af.png)
Немного о расширениях:
H4M  - Видео формат Gamecube
THP  - Видео формат GameCube и Wii
DOL -  то же самое, что и EXE в Windows, то бишь исполняемый файл.
DSP - чаще, звук GameCube
TPL - Графика GameCube
ARC - архив GameCube, может быть RARC, может YAZ, может U8, а может вообще свой формат.
 
Открываем папку "DATA" и смотрим файлики, видим несколько THP файлов, то бишь видео файлов, всё остальное WAD и CSF, следовательно нам они и нужны, но какие именно? Их же куча.
Об этом поговорим в следующей части, скажу лишь вот что, в папке DATA есть файлы с префиксом en_*.wad(где * - любые другие символы). Так что они первые будут подвергнуты "взлому".
 
Ну а сейчас поставим цели:

  • Найти шрифт
  • Разобрать и написать софт для работы с WAD и CSF
  • Найти текст и разобрать его
  • Определить формат текстур
На счёт шрифта, файла с именем FONT или подобного нету, но у меня есть предположения на некоторые файлы

  • Start.DOL - Данный файл ВСЕГДА надо проверять на наличие текста и шрифта(если он не найден до этого) !ЗАПОМНИТЕ!
  • System.WAD
  • Global.WAD
  • Arial3d.WAD
Данные файлы мы тоже проверим, но в следующей части.
 
Если вам понравилася данная тема и вы хотите видеть продолжение, то отписывайтесь, продолжим :)
 
 
 
 
 
ЧАСТЬ 2 - Разбираем WAD
 
Спойлер
P.S. Прошу Админа данный текст скопировать в шапку и удалить это сообщение.
Я решил для начала разобрать WAD, чтобы уже рассмотреть по отдельности каждый файл в архиве.

Начнём с открытия файла в HEX редакторе, давайте ка откроем файл System.WAD и посмотрим содержимое:
(http://s7.hostingkartinok.com/uploads/images/2014/11/658791c7bca2db7e3aa655514fa646db.png)
А теперь расскажу о том, что я выделил:
Чёрный - TOC, можно использовать как проверку, тот ли архив открываем. Никогда не меняется. Скорей всего указывает на блок TOC.
Тёмно-серый - Размер блока TOC, блок TOC начинается c $1C.(Значение, перед которым стоит "$", означает HEX значение)
Серый - Кол-во файлов.
А дальше идёт TOC, на каждый файл выделяется $20, то есть будет цикл считывания от 1 до Кол-во файлов.

Красный - Имя файла, максимальный размер $10.
Оранжевый - Расширение файла, максимальный размер $4.
Жёлтый - Поинтер(указатель) на начала блока с файлом.
Синий - Размер блока с файлом.

А вот теперь последнее:
Коричневый - Перед каждым блоком с файлом есть информация в размере $1C, посмотрев на эти $1C, можно понять, что это информация о блоке, который идёт после неё. Она нам не нужна, т.к. мы считали эту информацию из TOC, но работать с ней придётся, т.к. это понадобится для запаковки

Разобрав этот архив, приступим к написанию программы для распаковки.

Я составил структуру WAD, для удобности:

Type
TTOCBlock = record
   NameFile : array[1..199] of AnsiString;//Имя файла
   ExtFile : array[1..199] of AnsiString;//Расширение файла
   PointerFile : array[1..199] of integer;//Позиция файла
   SizeFile : array[1..199] of integer;//размер файла
end;

Type
TInfoBlock = record
   NameFile : array[1..199] of AnsiString;//Имя файла
   ExtFile : array[1..199] of AnsiString;//Расширение файла
   SizeFile : array[1..199] of integer;//размер файла
end;

Type
TWADFile = record//Big-Endian
   CheckTOC : AnsiString;//Переходим на $10 и читаем 3 байта в String, если String = 'TOC', то позиция стримки + 1
   SizeTOCBlock : Integer;//Размер TOC
   CountFiles : Integer;//Кол-во файлов
   TOCBlock : TTOCBlock;
   InfoBlock : TInfoBlock;
end;
Ну что ж, начнём писать программу. Весь код я постараюсь комментировать, для удобности.

Открываем Delphi XE7(можно и постарее, просто у меня стоит именно эта версия), создаём VCL Forms Application(Да, я люблю именно программы на формах) и копируем мной составленную структуру выше "var":
(http://s7.hostingkartinok.com/uploads/images/2014/11/e7b613eb1cc782aba81c00656c5958c9.png)
(старый скрин, вместо string - AnsiString)
После "var" напишем
WADFile : TWADFile;
F:TFileStream;
Так же, после {$R *.dfm} добавим такой код:
function SwapEndian(Value: integer): integer; register; overload;
asm
  bswap eax
end;
Он понадобится, чтобы конвертировать Little-Endian значение в Big-Endian и наоборот.

Теперь добавим на форму OpenDialog, SaveDialog, MainMenu, StringGrid, StatusBar и ProgressBar.

Стандартное имя компонентов я менять не буду, чтобы вы не запутались.

Так, начнём с оформления:
Меню я сделал такое, пока сойдёт :D
(http://s7.hostingkartinok.com/uploads/images/2014/11/79a918da3b46c2eab057cbae6a2cba7e.png)
Теперь настроим StringGrid:
Align = alClient
ColCount = 3
FixedCols = 0
Options -> goRowSelect = Включить
RowCount = 2

Так же добавим 3 панели у StatusBar
У 1 панели ставим Width = 100, у 2 Width = 300 и Text="File:", у 3 Width Можно любой, но не меньше 100, а Text="Mode:".

Так, вроде всё, перейдём к написанию кода, создадим у Form1 процедуру OnCreate(Надеюсь, вы умеете самое простое).

Пишем туда такой код:

begin
with ProgressBar1 do//Добавляем progressbar на 1 панель statusbar
  begin
    Parent := StatusBar1;
    Position := 0;
    Top := 2;
    Left := 1;
    Height := StatusBar1.Height - Top;
    Width := StatusBar1.Panels[0].Width - Left;
  end;
StringGrid1.Cells[0,0]:='Name File';//Пишем текст в первую строку
StringGrid1.Cells[1,0]:='Pointer';
StringGrid1.Cells[2,0]:='Size';
StringGrid1.ColWidths[0]:=450;//Меняем размер у колонок
StringGrid1.ColWidths[1]:=80;
StringGrid1.ColWidths[2]:=80;
end;
Так же у формы создадим процедуру OnCanResize и напишем туда этот код:
StringGrid1.ColWidths[0]:=StringGrid1.Width-(StringGrid1.ColWidths[1]+StringGrid1.ColWidths[2]+10);//При изменении размера формы, расширяем колонку с названием файла
Ещё добавим фильтр у OpenDialog
WAD File (*.wad)|*.wad
Вот и всё, с оформлением пока всё.

Ну что ж, начнём писать процедуру распаковки:
Давайте ка я распишу как будет работать распаковка:

  • Переходим на $10 и читаем 3 байта, если это TOC, то продолжаем работу и , если нет, то выводим сообщение об ошибке.
  • К позиции стримки(Stream) прибавляем 1 и считываем 4 байта, конвертируем из Big-Endian в Little-Endian с помощью функции, которую мы написали с самого начала (SwapEndian) и сохраняем в WADFile.SizeTOCBlock.
  • Считываем 4 байта, конвертируем из Big-Endian в Little-Endian и сохраняем в WADFile.CountFiles.
  • Начинаем цикл с 1 до WADFile.CountFiles и в цикле считываем по одному байту, пока не встретится $00, сохраняем размер от прошлой позиции стримки до $00, читаем в WADFile.TOCBlock.NameFile столько, сколько получили при считывании до позиции $00. Дальше переходим к позиции расширения и считываем его в WADFile.TOCBlock.ExtFile. Потом читаем 4 байта, конвертируем, записываем в WADFile.TOCBlock.PointerFile, читаем ещё 4 байта, конвертируем, сохраняем в WADFile.TOCBlock.SizeFile, добавляем к позиции стримки 4, добавляем всё данные в StringGrid и на этом цикл кончается.
А теперь пишем процедуру для распаковки:
Добавим

procedure ExtractWad;
procedure ExtractBlock(NumFile:Integer);
в Type формы(в самом верху)
А теперь добавим саму процедуру распаковки:

Procedure TForm1.ExtractWad;//Узнаём всё о файлах
var
I,TempPos,Size:Integer;
B:Byte;
S:String;
begin
F:=TFileStream.Create(OpenDialog1.FileName,fmOpenReadWrite);
F.Position:=$10;
SetLength(WADFile.CheckTOC,3);
F.Read(WADFile.CheckTOC[1],3);
F.Position:=F.Position+1;
if WADFile.CheckTOC='TOC' then
begin
F.Read(WADFile.SizeTOCBlock,4);
WADFile.SizeTOCBlock:=SwapEndian(WADFile.SizeTOCBlock);
F.Read(WADFile.CountFiles,4);
WADFile.CountFiles:=SwapEndian(WADFile.CountFiles);
StringGrid1.RowCount:=WADFile.CountFiles+1;
StatusBar1.Panels[2].Text:='Mode:WAD File';
StatusBar1.Panels[1].Text:='File:'+OpenDialog1.FileName;
for I := 1 to WADFile.CountFiles do
begin
TempPos:=F.Position;
Size:=1;
F.Read(B,1);
while B<>$00 do
begin
F.Read(B,1);
Size:=Size+1;
end;
Size:=Size-1;
F.Position:=TempPos;
SetLength(WADFile.TOCBlock.NameFile[i],Size);
F.Read(WADFile.TOCBlock.NameFile[i][1],Size);
while b=$00 do
f.Read(b,1);
f.Position:=f.Position-1;
SetLength(WADFile.TOCBlock.ExtFile[i],3);//временно
F.Read(WADFile.TOCBlock.ExtFile[i][1],3);
f.Position:=f.position + 1;
F.Read(WADFile.TOCBlock.PointerFile[i],4);
WADFile.TOCBlock.PointerFile[i]:=SwapEndian(WADFile.TOCBlock.PointerFile[i]);
F.Read(WADFile.TOCBlock.SizeFile[i],4);
WADFile.TOCBlock.SizeFile[i]:=SwapEndian(WADFile.TOCBlock.SizeFile[i]);
F.Position:=F.Position+4;
StringGrid1.Cells[0,i]:=WADFile.TOCBlock.NameFile[i]+'.'+WADFile.TOCBlock.ExtFile[i];
StringGrid1.Cells[1,i]:='0x'+IntToHex(WADFile.TOCBlock.PointerFile[i],WADFile.TOCBlock.PointerFile[i].Size);
StringGrid1.Cells[2,i]:='0x'+IntToHex(WADFile.TOCBlock.SizeFile[i],WADFile.TOCBlock.SizeFile[i].Size);
end;
end else ShowMessage('Это не WAD:(');
end;

procedure TForm1.ExtractBlock(NumFile: Integer);//Извлечение определённого блока
var
Temp:TFileStream;
I:Integer;
begin
SaveDialog1.FileName:=WADFile.TOCBlock.NameFile[NumFile];
SaveDialog1.DefaultExt:=WADFile.TOCBlock.ExtFile[NumFile];
if not SaveDialog1.Execute then exit else begin
  f.Position:=WADFile.TOCBlock.PointerFile[NumFile];
  ShowMessage(IntToHex(WADFile.TOCBlock.SizeFile[NumFile],4));
  Temp:=TFileStream.Create(SaveDialog1.FileName,fmCreate);
  Temp.CopyFrom(F,WADFile.TOCBlock.SizeFile[NumFile]);
  Temp.Free;
end;
end;
Теперь на кнопку Файл->Открыть повесим код

if not OpenDialog1.Execute then exit else begin
ExtractWad;
end;
А на кнопку Архив->Извлечь файл повесим код

ExtractBlock(StringGrid1.Row);Я ещё этот код повесил на двойной клик по StringGrid, мне так удобней ^_^
Ну, вроде, всё работает B)
Давайте напишем ещё функцию извлечения всех файлов и пойдём пить чай с тортиком.
 
Так, сначала в Uses добавим ShlObj, ActiveX, потом в код добавим функцию(лучше в начало):

function AdvSelectDirectory(const Caption: string; const Root: WideString;
var Directory: string; EditBox: Boolean = False; ShowFiles: Boolean = False;
AllowCreateDirs: Boolean = True): Boolean;
function SelectDirCB(Wnd: HWND; uMsg: UINT; lParam, lpData: lParam): Integer;
stdcall;
var
PathName: array[0..MAX_PATH] of Char;
begin
case uMsg of
BFFM_INITIALIZED: SendMessage(Wnd, BFFM_SETSELECTION, Ord(True), Integer(lpData));
end;
Result := 0;
end;
var
WindowList: Pointer;
BrowseInfo: TBrowseInfo;
Buffer: PChar;
RootItemIDList, ItemIDList: PItemIDList;
ShellMalloc: IMalloc;
IDesktopFolder: IShellFolder;
Eaten, Flags: LongWord;
const
BIF_USENEWUI = $0040;
BIF_NOCREATEDIRS = $0200;
begin
Result := False;
if not DirectoryExists(Directory) then
Directory := '';
FillChar(BrowseInfo, SizeOf(BrowseInfo), 0);
if (ShGetMalloc(ShellMalloc) = S_OK) and (ShellMalloc <> nil) then
begin
Buffer := ShellMalloc.Alloc(MAX_PATH);
try
RootItemIDList := nil;
if Root <> '' then
begin
SHGetDesktopFolder(IDesktopFolder);
IDesktopFolder.ParseDisplayName(Application.Handle, nil,
POleStr(Root), Eaten, RootItemIDList, Flags);
end;
OleInitialize(nil);
with BrowseInfo do
begin
hwndOwner := Application.Handle;
pidlRoot := RootItemIDList;
pszDisplayName := Buffer;
lpszTitle := PChar(Caption);
ulFlags := BIF_RETURNONLYFSDIRS or BIF_USENEWUI or
BIF_EDITBOX * Ord(EditBox) or BIF_BROWSEINCLUDEFILES * Ord(ShowFiles) or
BIF_NOCREATEDIRS * Ord(not AllowCreateDirs);
lpfn := @SelectDirCB;
if Directory <> '' then
lParam := Integer(PChar(Directory));
end;
WindowList := DisableTaskWindows(0);
try
ItemIDList := ShBrowseForFolder(BrowseInfo);
finally
EnableTaskWindows(WindowList);
end;
Result := ItemIDList <> nil;
if Result then
begin
ShGetPathFromIDList(ItemIDList, Buffer);
ShellMalloc.Free(ItemIDList);
Directory := Buffer;
end;
finally
ShellMalloc.Free(Buffer);
end;
end;
end;
Так, теперь в Type формы добавим:
procedure ExtractWadAll(Path:String);
И начнём писать функцию для распаковки всех файлов:
 

Procedure TForm1.ExtractWadAll(Path:String);
var
I:Integer;
Temp:TFileStream;
begin
ProgressBar1.Max:=WADFile.CountFiles;
if path<>'' then
for I := 1 to WADFile.CountFiles do
begin
F.Position:=WADFile.TOCBlock.PointerFile[i];
Temp:=TFileStream.Create(Path+'\'+WADFile.TOCBlock.NameFile[i]+'.'+WADFile.TOCBlock.ExtFile[i],fmcreate);
Temp.CopyFrom(F,WADFile.TOCBlock.SizeFile[i]);
Temp.Free;
ProgressBar1.Position:=i;
end;
ProgressBar1.Position:=0;
ShowMessage('Готово');
end;
Осталось только добавить на кнопку извлечения всех файлов вот этот код:
var
s : string;
begin
AdvSelectDirectory('Выберите папку для распаковки', '', s, False, False, True);
ExtractWadAll(s);
end;
Всё, готово, радуемся от того, какие мы молодцы. :)
На этом урок заканчивается, в следующем уроке мы продолжим разработку программы и может быть начнём искать шрифт или текст, спасибо за чтение ;)
Если будут вопросы - спрашивайте.
Исходники данного проекта в прикреплённых файлах, под именем SAEditorSourceLesson2.rar
Ваш, TTEMMA
Название: Re: Учимся "переводить" игры на GameCube
Отправлено: SPOT от 07 ноября 2014, 18:40
Полезная теме, продолжай в том же духе. Особенно интересует шестой пункт:

Цитировать 
*Знания программирования, компилятор Delphi XE7(Да, да, я использую Delphi)
Страсть как интересно, что там будем делать :)
Название: Re: Учимся "переводить" игры на GameCube
Отправлено: TTEMMA от 07 ноября 2014, 18:50
ЦитироватьПолезная теме, продолжай в том же духе.
Рад, что кому-то нравится, тогда продолжу.

Цитировать 
Страсть как интересно, что там будем делать
Ну я уже построил маленькую структуру WAD, так что в скором времени будет вторая часть ;)

Type
TWADFile = record;//Big-Endian
CheckTOC : String;//Переходим на $10 и читаем 3 байта в String, если String = 'TOC', то позиция стримка + 1
SizeTOCBlock : Integer;//Размер TOC
CountFiles : Integer;//Кол-во файлов
NameFile : array[1..99] of String;
ExtFile : array[1..99] of String;
PointerFile : array[1..99] of integer;//Позиция файла
SizeFile : array[1..99] of integer;//размер файла
end;
//Перед каждым файлом в архиве есть Блок из TOC
Название: Re: Учимся "переводить" игры на GameCube
Отправлено: Slik от 07 ноября 2014, 20:05
Цитата: TTEMMA от 07 ноября 2014, 18:50Type
TWADFile = record;//Big-Endian
CheckTOC : String;//Переходим на $10 и читаем 3 байта в String, если String = 'TOC', то позиция стримка + 1
SizeTOCBlock : Integer;//Размер TOC
CountFiles : Integer;//Кол-во файлов
NameFile : array[1..99] of String;
ExtFile : array[1..99] of String;
PointerFile : array[1..99] of integer;//Позиция файла
SizeFile : array[1..99] of integer;//размер файла
end;
//Перед каждым файлом в архиве есть Блок из TOC
Что такое TOC?
Название: Re: Учимся "переводить" игры на GameCube
Отправлено: TTEMMA от 07 ноября 2014, 21:01
ЦитироватьЧто такое TOC?  
Table Of Contents
Там хранится многое, что связано с каждым файлом(поинтер, размер, имя и т.д.)
В следующем уроке всё поймёте;)
Название: Re: Учимся "переводить" игры на GameCube
Отправлено: Greengh0st от 08 ноября 2014, 10:02
Отлично, как закончишь запилим видео урок.
Название: Re: Учимся "переводить" игры на GameCube
Отправлено: Greengh0st от 08 ноября 2014, 19:57
Отлично, терь её можно будет переводить?))) поправил всякие бяки типа мои выделения и опечатку)))
Название: Re: Учимся "переводить" игры на GameCube
Отправлено: TTEMMA от 08 ноября 2014, 20:21
Переводить не спеши, еще не все разобрали)
За исправления спасибо,было бы круто в шапку перенести)
Название: Re: Учимся "переводить" игры на GameCube
Отправлено: Greengh0st от 08 ноября 2014, 20:45
Надо бы под спойлеры спрятать, а то капец как много места занимают.
Название: Re: Учимся "переводить" игры на GameCube
Отправлено: TTEMMA от 09 ноября 2014, 11:41
Цитата: Greengh0st от 08 ноября 2014, 20:45Надо бы под спойлеры спрятать, а то капец как много места занимают.
Да и тег КОД пропал там, где нужен, при переносе:(
А почему я больше не могу редактировать свой пост?
Название: Re: Учимся "переводить" игры на GameCube
Отправлено: Greengh0st от 09 ноября 2014, 14:28
Вопросы к админу)))
Название: Re: Учимся "переводить" игры на GameCube
Отправлено: admin от 10 ноября 2014, 11:55
Цитата: TTEMMA от 09 ноября 2014, 11:41А почему я больше не могу редактировать свой пост?
 
Ограничение форму по редактированию сообщений пользователями. Вроде бы пользователь может редактировать своё сообщение в течение 10 мин.
Название: Re: Учимся "переводить" игры на GameCube
Отправлено: TTEMMA от 10 ноября 2014, 18:30
Жаль, а поправить 10 мин. на другое значение нельзя?
Спасибо за исправление и добавление тега код, сам то поправить не могу)
P.S. В начале второго урока есть ещё участок, который нужно в КОД всунуть, это от Type до end;
Название: Re: Учимся "переводить" игры на GameCube
Отправлено: Mefistotel от 11 ноября 2014, 02:35
Цитата: admin от 10 ноября 2014, 11:55 

Цитата: TTEMMA от 09 ноября 2014, 11:41А почему я больше не могу редактировать свой пост?
 
Ограничение форму по редактированию сообщений пользователями. Вроде бы пользователь может редактировать своё сообщение в течение 10 мин.
 
Интересное ограничение.
А убрать его нельзя или увеличить хотя бы до 24 часов время редактирования?
Название: Re: Учимся "переводить" игры на GameCube
Отправлено: admin от 11 ноября 2014, 20:01
TTEMMA, поместил тебя в специальную группу, теперь ты можешь редактировать свои сообщения. Проверь нормально ли функционирует. Кому ещё нужна подобная возможность, обращайтесь.
Название: Re: Учимся "переводить" игры на GameCube
Отправлено: admin от 11 ноября 2014, 20:03
Цитата: Mefistotel от 11 ноября 2014, 02:35Интересное ограничение.
 
А убрать его нельзя или увеличить хотя бы до 24 часов время редактирования?
 
Подобная практика существует на множестве форумах.
Название: Re: Учимся "переводить" игры на GameCube
Отправлено: TTEMMA от 11 ноября 2014, 22:10
Цитата: admin от 11 ноября 2014, 20:01TTEMMA, поместил тебя в специальную группу, теперь ты можешь редактировать свои сообщения. Проверь нормально ли функционирует. Кому ещё нужна подобная возможность, обращайтесь.
Всё, править могу, спасибо большое :)
Название: Re: Учимся "переводить" игры на GameCube
Отправлено: admin от 12 ноября 2014, 10:47
TTEMMA, перезалей файл SAEditor.rar. Видимо при переноси сообщения в шапку, он исчез.
Название: Re: Учимся "переводить" игры на GameCube
Отправлено: Lin от 19 февраля 2016, 16:34
Когда будет продолжение темы?