Да уж, это было непросто! Интересно и познавательно. Но такую вещь на расслабоне не почитаешь, это настраиваться надо. А вообще – круто! Но дико. В том смысле, что может в одном или в другом, но ВСЮДУ – я бы такие выкрутасы с красивыми словечками выдавать не смог, признаю…
Ха, возможно я тоже весьма отравлен канцеляритом. И обычно я как бы считал это преимуществом, потому что много когда владение им играет большую пользу. Другое же дело, что он и не должен ни для чего требоваться, но это уже не ко мне, я просто приспособился как мог. Но я ведь понимаю, когда моя речь свободная – канцеляричу как хочу – а когда я создаю некий продукт, где этому не место – и легко избавляюсь от него. Однако ведь автор книги призывает-то как раз из намеренного искоренения его из обыденной жизни в том числе.
Вообще, книга переполнена её личным отношением ко ВСЕМУ. Хотелось бы больше конкретики, больше точных примеров и ничего лишнего. Нет, там очень и очень много примеров, но он часто разбавлялись возгласами «ну как так, ну сколько ж можно». Понятно конечно, что книга должна быть яркой и мотивирующей, но я-то больше предпочитаю «справочники». Хотя думаю, многим такой стиль изложения наоборот понравится.
Ой, а с этим улучшением-украшением переводимых текстов! Это надо постоянно как бы кричать самому себе: – Бред. – Но так в оригинале! – Что это значит? – Ну это как бы… – Нет. Ещё! – Это когда… – Так, и? – Там вот как бы… – Проще! – Ну там всё… – Ещё проще!! – Не знаю! Ну это типа… – Да что это!? – Это бывает, когда… – Ну что это такое? )) – Да это же! – Ага, во-от! – И ещё!.. – Всё, так и напиши.
И так на каждую фразу. На примерах показывалось, как битва за каждое слово выигрывает бой за всю фразу. Хм… В принципе, это именно то, что делает Томас в переводе Spyro2.
Нора Галь агитирует за «дерзкий» перевод! О, и зря вы сказали, что последние главы можно не читать. Это же «Best Practices»! Ага, диву даёшься, как они выбрали именно такой вариант перевода. А ещё больше нравятся описания – которые следует бы совать в нос тому, кто в очередной раз заявит «имена не переводятся» или «так написано в оригинале».
Отсюда вытекает ещё одна проблема книги. Ну не будь она такой большой, такой тяжёлой для чтения и вникания… Вот кому я могу её порекомендовать? Кому захочется в ней копаться? Тому, кто плохо переводит? Не, если он аж настолько плохо переводит, что только полноценное прочтение такой книги ему поможет – то он и читать её не будет, у него сил и осознанности не хватит. Тому, кто хорошо переводит? Да, он прочтёт. Но весьма нескоро, у него и так много дел. Просто показать нужный отрывок в нужный момент? Но тогда не дойдёт вся мораль, весь напор повествования книги, а значит – и авторитет прочтённого.
Вот можно сказать, что я познал истину (это как фильм «Дух времени», наверное). Не то чтобы я её не знал, но теперь я точно уверен в ней! Но вот «передать» эту истину через эту книгу почти невозможно. Нельзя заставить прочитать её. Тем более, нельзя заставить вникнуть в текст! (Даже я пропускал некоторые абзацы, дойдя до их середины – я и слов таких не знаю, и произведения эти не читал… Хотя теперь может «маленького принца» прочту, а то всё муми-тролль, муми-тролль…) Нельзя «просто сослаться» даже на отрывок, и ожидать, что перешедший по ссылке просветлеет.
Хотите обратный пример? Берём хренового переводчика за шкирку, и тыкаем сюда: http://translations.ted.org/wiki....ий_язык Объявляем это истиной, и приказываем следовать. Не знаю, но по крайней мере одного переводчика, всюду писавшего в субтитрах «Вы» с большой буквы – мы таки переубедили. Но не только одной этой ссылкой… (причём жертва отбивалась неким правилом русского языка, в котором говорилось, что «на "Вы" нельзя обращаться к нескольким лицам», из чего якобы следовал вывод, что к одному лицу – можно и нужно.)
Тут – как я пытался агитировать за неё среди тамошних переводчиков:
Есть довольно полезная книга: http://royallib.com/book/gal_nora/slovo_givoe_i_mertvoe.html Интересно, знают ли о ней современные переводчики – такие как мы – ведь мне иногда кажется, что нет. Польза от книги огромная, но у неё есть одна проблема: это не для лёгкого чтения, и чтобы её прочитать, нужно поставить себе серьёзную цель.
Каждый раз, встречая «имена не переводятся» или «так написано в оригинале», мне хочется бесконечно апеллировать к этой книге. Но вытаскивать оттуда цитаты не так авторитетно, как позволить самой книге открыть глаза другим.
Одно дело, когда переводчик ошибся, что-то пропустил или неправильно понял оригинал – достаточно лишь объяснить и может даже поспорить. Но если же ошибочное мнение закоренело – то изменить его будет очень и очень непросто, особенно простыми разговорами. А тут – собрано всё самое яркое, объясняются (может даже слишком часто) последствия, вытекающие из неправильного подхода к переводу. Кажется, всем достаточно просто прочитать всё это – и качество перевода возрастёт. Либо из-за общей смены отношения, либо из-за более частого включения мозга там, где раньше использовалось «первое слово по словарю», а где-то даже из-за скромности самого переводчика, который не рискнёт предлагать плохой вариант, заведомо осознавая его низкокачественность.
SubCmpAlgo v1.1 – а вот что ещё я собрал. Далее – большая сборная копипаста того, как я создавал алгоритм сравнения субтитров. Это из разных диалогов и источников, и то лишь самое основное. Сначала я обсуждал задачу с математиками и программистами, а затем уже показывал результат переводчикам из TDT.
Короче, у меня есть две числовые прямые, на них – непересекающиеся отрезки. Я накладываю эти прямые друг на друга, и хочу порезать на кусочки. Моя цель – как-то соотнести отрезки на одной прямой с отрезками на другой.
Задание нечёткое, могу лишь примерно описать, чего хочу получить: Если отрезки начинаются в одинаковых местах – резать по ним. Если отрезки чуть-чуть сдвинуты – всё равно резать (через какую точку пройдёт – неважно, меня только интересуют группы соотнесения отрезков по участкам) Если отрезок не соответствует никакому на второй – пофиг, резать его одного. Если один отрезок поглощает другой – они должны оказаться в одной группе. Когда один отрезок поглощает несколько – те должны быть объединены в его группу. И самое главное: отрезок не должен попасть более чем в одну группу.
Пока у меня идея – считать пустые промежутки между отрезками – тоже отрезками, тогда прямые просто разобьются точками. Потом найти пару противолежащих точек, между которыми наименьшее расстояние – и разбить по ним. Продолжать до тех пор, пока получаются разрезы.
Верный способ? Или есть контр-пример?
Вообще, это две разные версии субтитров к одному и тому же видео, которые я хочу построчно сравнить. Но тайминг разный, и количество строк разное. Но они _примерно_ на тех же местах по времени.
Иногда в одном файле фраза одна и длинная, а в другом – две коротких. Тогда они должны быть соединены, чтобы соответствовать.
Так. У меня есть три файла субтитров. Субтитры – это наборы текстовых реплик, персонажей и тайминга. Тайминг – это пара начало+конец каждой реплики относительно всего файла. Пример:
0:17:11.42,0:17:14.59,Rarity,Who cares what some stuffy unicorn thinks of the food here. 0:17:14.59,0:17:16.30,Rarity,It's exquisite. 0:17:16.58,0:17:17.68,PinkiePie,That's true. 0:17:18.24,0:17:21.64,Rarity,And you don't need three silly hooves in your window to prove it. 0:17:21.64,0:17:23.14,PinkiePie,That's double true. 0:17:23.44,0:17:26.48,Rarity,You just need ponies in here to give it a chance. 0:17:26.82,0:17:29.37,Rarity,Ponies that would tell everypony else in Canterlot 0:17:29.37,0:17:31.94,Rarity,that the "Tasty Treat" is best food in the city! 0:17:32.16,0:17:34.24,PinkiePie,That's true times three!
– некоторые концы совпадают с началами следующих фраз. Но это не запрещает им пересекаться. Вначале я хочу взять представить их как отрезки во времени, и взять объединение. Я соберу пересекающиеся фразы в кусочки большего размера, объединив и их текст по порядку (вчера часа в три ночи я думал, что я уже смог запрограммировать это, но теперь вижу, что нет…) Теперь я имею непересекающиеся (но возможно, касающиеся) отрезки, имеющие начала, концы и свой текст.
Так я поступаю с двумя файлами субтитров. Основная задача – вывести всё это в таблицу, как в той, что я показал. По строчкам должны располагаться подобранные реплики. Но основная проблема в том, что тайминг в обоих файлах на за что не совпадёт (его делали разные люди на слух). Более того, разбивка на реплики разная: где-то могут быть большие и длинные фразы, а где-то они же (это субтитры к одному и тому же видео) они разбиваются на более короткие.
Вторая проблема в том, что сам тайминг сделан под разные релизы видео, и может быть линейное расхождение в около секунды. Ну тут какую-нибудь линейную регрессию можно устроить.
Но основная задача – сопоставить субтитры. В итоге мне нужно, чтобы программа автоматически собирала напротив друг друга правильные фразы, которые соответствуют друг другу. Без ручного выравнивания.
Предполагаем, что на шкале времени есть некая «информация», а две линии – это субтитры. На линиях – отрезки, которые представляют собой фразы по таймингу. Считаем, что они доносят ту же самую информацию, но не синхронны между линиями. Нужно порезать отрезки на группы, чтобы в каждую группу старались попасть отрезки с одинаковой информацией. Но резать можно только по границам отрезков.
Понять бы, что считать… Например, нужно ли мне максимизировать количество групп? Видимо, нет. Потому что уж если две к двум фразы никак не сходятся – то их и нужно оставить парой. Грубый пример: 1) – я – умею разделять отрезки
2) – я умею разделять – отрезки
Тут нет соответствия между фразами, их нужно оставить «две на две». Если бы в одном из них была всего одна целая фраза – она должна была бы соответствовать сразу двум.
Но чаще всего будет соответствие один к одному. Проблема в том, что программа должна предъявить лучшее разделение, основываясь исключительно на тайминге фраз, а не на их смысле в тексте, как делается вручную.
И наконец, у меня не два файла, а три. Ну, в перспективе хочется сделать общий случай для большего количества. Но три нужно точно. Хотя, я точно знаю, что два из них – ОДИНАКОВЫ. Но это в моём частном случае. Тут бы для двух хотя бы решить, да…
Но мне кажется, если алгоритм будет грамотный, его можно и обобщить. Однако там уже придётся потребовать хотя бы независимость от порядка, в котором на вход приходят файлы, и чтобы при одинаковости нескольких из них алгоритм дал бы тот же вердикт, как если бы файлов было меньше – без этих самых копий.
Надоело оперировать абстрактными понятиями. Собираюсь выгрузить субтитры в условную временную шкалу и по факту посмотреть, как именно по статистике на ней будут расположены настоящие точки начал и концов реплик…
Синяя шкала короче, получается временной лаг. Если настроить на три секунды (поле 300) – то примерно на середине экрана как раз выравнивается. Светлые полоски – «концы» отрезков (тёмные – начала), если поверх них начало следующего – то не видно.
Это работает! Для каждой точки ищу ближайшую точку на второй прямой, и запоминаю её номер. Если две точки на разных прямых считают друг друга ближайшими – то режу по ним. Проблем нет ни с поиском, ни с длинными невыгодными разрезами – потому что если ближайшая точка уже занята другим разрезом, то значит для неё текущая не ближайшая, и резать не надо. Как обобщение на случай нескольких прямых можно рассматривать попарную близость – пусть каждая точка запоминает ближайших на остальных прямых. И резать через всю группу, если они все считают друг друга ближайшими.
Осталась проблема таймлага. Он дискретный, а не плавный. То есть длительность и скорость всех диалогов одинакова. Но во время уходов на рекламу синхронизация теряется. Возможно, эти кусочки можно выявить автоматически, потому что разрыв отрезков очень большой (но подбирать надо как-то адаптивно). Потом порезать по рекламе, и устроить регрессию.
Либо проще – взять некий порог (возможно адаптивно), меньше минимальной длительности этих самых пауз от вырезанной рекламы. Потом пройти по всем отрезкам, и если паузы больше, чем порок – сделать её размером ровно с порог, чтобы начала очередных отрезков совпали.
Надо бы вывести все длины промежутков между всеми отрезками и построить таблицу или график…
Ого, даже порогом ограничить вот так просто не получается. Если в одном варианте субтитров, скажем, заставочная песня сопровождена текстом, а в другой – нет, то пустота вместо неё сворачивается в порог, и всё дальнейшее соответствие неверно.
Как-то параллельно надо что ли длинные промежутки пауз искать…
Выбираем некоторый порог, скажем, три секунды. Далее фиксируем первую фразу на одной и другой прямой. Ищем на каждой прямой вперёд первую ближайшую паузу между отрезками, превосходящую порог. Если не найдено ни на одной, либо какая-то исчерпана (если мы начали искать от её конца – когда зафиксированное начало уже ушло, окончание алгоритма) – выходить из выравнивания и перейти к основному алгоритму разбиения.
Теперь, у нас есть две дырки (если одна, то втору считаем максимально удалённой). Берём ту из них, конец которой ближе по времени.
Теперь на соседней прямой ищем ближайшую точку начала отрезка, которая соответствует началу следующего отрезка за нашей дыркой на нашей прямой.
Выравниваем! Двигаем все последующие точки на одной из прямых вперёд. На той, точка выравнивания которой ранее (мы же взяли одну точку, и искали соответствующую ближайшую, которая могла быть как до, так и после неё).
Переносим фиксирование на точки, следующие за теми, по которым мы выровняли, и повторяем алгоритм.
О, и я даже придумал, как автоматически выбирать порог! Пусть он сначала будет минимальным – полсекунды. Каждый раз, когда мы собираемся выровнять – проверяем, превосходит ли добавляемая величина этот порог. И если да, то отменяем все сделанные манипуляции, сбрасываем массив и увеличиваем порог. Скажем, ещё на полсекунды. И повторяем всё заново до тех пор, пока выравнивание ни разу не перестанет превышать его. Ага, тут можно даже бинарный поиск применять, но это уж чересчур. Добавление полсекунды и полный пересчёт вполне работают, тем более что чем меньше порог – тем быстрее произойдёт сброс.
А ещё я думал устроить регрессию на участках, которые получаются выравниванием, но вроде и без этого всё отлично вышло.
Белые горизонтальные линии на страничке – разрезы выравнивания. Рядом есть вертикальная чёрточка – на столько были сдвинуты вперёд реплики на соответствующей прямой.
Всё, осталось лишь обобщить на три и более прямых…
Фу-у, я с многомерным массивом запарился…
Не могу сообразить, как попарную взаимность получить. Вот у меня короче что есть: – N прямых. – На каждой из них P(n) точек. – Каждая из них считает «ближайшей» Bn(i,m) одну из точек на каждой из оставшихся прямых (n≠m)
Я, например, храню это вот в таком массиве: M[n][i][m]=j, где n – исходная прямая (0..N-1) i – номер точки на ней (0..P(n)-1) m – целевая прямая (0..N-1) j – номер точки на целевой (0..P(m)-1)
Изначально я хотел пройти по нему, и делать t=M[n][i][m]; if (M[m][t][n]==i) {/* у точек взаимная близость */}
, но оказалось что точки других прямых, которые текущая точка на текущей прямой считает ближайшими к себе, даже если они в свою очередь для этой прямой считают данную точку ближайшей и к себе – они не обязаны быть ближайшими между собой!
Для двух прямых это неверно. Для трёх – определяется очень просто (достаточно проверить взаимную близость двух концов ближайших точек от текущей) , но для >=4 – вообще неочевидно, как проверять.
Я думал над чем-то вроде for(i=1;i<n;i++) { for(j=0;j<i;j++) { /* как-то проверять близость для прямых i и j */ }} , или например собирать в один массив все найденные близости, а если там уже есть – то проверять, что все имеющиеся тоже взаимно близки с добавляемым.
Но в обоих случаях надо как-то удобно представить данные, и как-то хорошо идти по ним циклами. Если что, массивы у меня безразмерные и ассоциативные, можно обращаться к неинициализированным элементам и реагировать на это; любой уровень вложенности.
Мне уже несколько раз казалось, что я придумал правильный метод хранения и обработки, но как только я начинаю программировать – понимаю, что всё совершенно не стыкуется…
Ещё у меня сверху нужно отодвигать часть файла, если одна из дорожек внезапно закончилась, чтобы другие не пытались безуспешно взаимно бизиться с ней. Но это вроде я смогу закодить.
Ну и сам финал – импорт .ass, экспорт .csv И интерактивное сравнение-голосование ^^
Мне нужно как-то высчитать «группы взаимности», в которых все точки между собой попарно ближайшие…
Более того, как обходить прямые? Если только одну – то она может оказаться короче других, и некоторые точки прочих не будут даже рассмотрены (а там есть условие, что они могут быть взаимно близки между собой, отбросив эту короткую). А если все – так дубли же!
Если мы сравниваем eng+a2a+tdt, то из того, что в последнем одна фраза, а в первых двух – две, то это значит, что меж ними нет никакой ещё одной группы. И лишние линии надо выкинуть.
Но я сделаю так: когда обнаруживается «большая» дырка на одно прямой – её концы отмечаются, чтобы во-первых, выровнять всё что дальше; а во-вторых – чтобы на этом промежутке её влияние на взаимность других прямых нивелировалось. Тогда, если останется лишь одна прямая – например, наша заставочная песня – каждая фраза ляжет в отдельную ячейку, как взаимная сама с собой.
Но если на нормальном промежутке хоть у кого-то нет взаимности – отбрасывать! На этом строилась первоначальная версия алгоритма для двух прямых, и она работала идеально! Вернее, проблема была только в одном месте, когда точки продолжительно идут в шахматном порядке. Но там даже не понятно, что делать (особенно потому что я самих фраз-то не вижу…), может будет понятно, когда таблицу с текстом получу…
У меня есть n линий, на которых стоят точки (одномерные). Везде далее индекс «c» можно не учитывать. В массиве f[h][i][c] – координаты i-той точки на h-той линии. На одной линии f[h].length точек.
Сначала я хочу найти для каждой точки на каждой из линий ближайшую точку. Завожу особый массив m[h][i][H][c]=j – это j-координата точки на H-той линии, и эта точка – ближайшая к точке i на h-той линии.
m=[]; for(h=0;h<n;h++){ // линии m[h]=[]; for(i=0;i<f[h].length;i++){ // их точки m[h][i]=[]; for(H=0;H<n;H++)m[h][i][H]={b:-1,e:-1}; // условно m[h][i][H][c]=-1; }}
– изначально заполняю «-1», то если ближайшая точка ни для кого не известна. Теперь:
for(c in {b:'',e:''}){ // условно c=0 for(h=0;h<n;h++){ // по всем линиям // для текущей линии: for(i=0;i<f[h].length;i++){ // по всем её точкам V=f[h][i][c]; // численное значение текущей точки m[h][i][h][c]=I; // сама для себя автоматически ближайшая for(H=0;H<n;H++){ // по всем другим линиям (и по своей тоже) d=-1;uu=-1; // счётчики расстояния обнуляем for(j=0;j<f[H].length;j++){ // по всем точкам «второй» линии v=V-f[H][j][c]; // расстояние от изначальной до текущей if(v<0)v=-v; // по модулю… if(d==-1||v<=d){ // если первая или ближе – d=v;uu=j; // запоминаем новое кратчайшее, и индекс }} // наконец, if(uu==-1)console.log(h,i,H,c); // (не выполнится, всё верно) m[h][i][H][c]=uu; // присваиваем в нужный массив }} // закончили }}
Проблемы возникают уже на следующем шаге:
for(c in {b:'',e:''})for(h=0;h<n;h++)for(i=0;i<f[h].length;i++)for(H=0;H<n;H++)if((v=m[h][i][H][c])>-1&&i!=m[H][v][h][c])m[h][i][H][c]=m[H][v][h][c]=-1;
Я пытаюсь проверить, считают ли какие-то точки друг друга ближайшими по взаимности, и если нет – отбрасываю их. Если v=m[h][i][H][c] – это для линии h и её точки i индекс ближайшей точки на линии H. Значит, если я возьму обратное, m[H][v][h][c] – то должен получить текущий же индекс, в том случае, если для линии H и этому индексу точки, ближайшей на текущей линии h будет иметь текущий индекс i.
Но в результате я получаю очевидные ложные срабатывания на точках, которые являются взаимно близкими. Всё, что у меня дальше в коде (а там я ищу группы попарной взаимной близости, когда все точки на разных прямый близки между собой) становится неверным.
И я не могу понять, в чём проблема. Входные данные вроде тоже проверял (точки отсортированы по возрастанию на своих линиях). Метод поиска ближайшей неоднократно менял – сейчас он, кстати, едва ли самый оптимальный на отсортированном-то массиве…
Инструкция: – поместить несколько разных .ass субтитров к одной серии пони в одну папку. – на страничке активировать элемент выбора файлов, и выделить их все (оптимально 2-3 файла) – нажать «открыть» в самом диалоге, и всё. Прокрутить до низу!
Он пытается определить, как файлы порезать на группы так, чтобы в них попали одинаковые по смыслу куски.
Умеет вырезать рекламу (с автоподбором порога), корректно обрабатывает интро, и небольшую линейную регрессию устраивает.
, правда я себе облегчил задачу в конце, когда понял, что не имеет смысла, скажем, сравнивать между собой лишь три из четырёх дорожек, когда одна уже кончилась или в ней дыра. Потому что в итоге это же для начисления балов, а так иначе что получается – что в одном столбце будет меньше ячеек, чем в других? И голоса за эти ущербные строчки потеряют смысл. То есть добавление пустого файла всё действительно ломает – его нельзя сравнить «построчно» с остальными, а значит и их разбиение на строчки должно пропасть. Зато, с другой стороны, добавление точной копии одного из файлов – вообще ничего не меняет, это да.
Готов, в той или иной степени, мой скрипт сравнения субтитров. Он выполняет две различные функции: 1) Позволяет получить численную субъективную оценку, сколько строчек лучше переведено у нас, чем у анонимов, и наоборот. Нужно просто кликнуть мышкой по лучшему из вариантов в таблице. 2) Позволяет по словам сравнить транскрипт анонимов с транскриптом от Хасбро. Вот: http://klimaleksus.narod.ru/Files/4/asscmp1V1.htm
Для пословного анализа, можно просто запустить анонимский английский и хасбро, в режиме Diff, без strict. Я сохранил его, можете просто открыть файл /diff через нижнюю форму загрузки файла.
А для быстрого сравнения нас с анонимами, открываете наш и их .ass в обычном режиме, этого уже достаточно. Но я добавил туда и английские варианты, чтобы во-первых, иметь ещё две категории оценок (итого пять: «не оценивается» / «мы выиграли» / «мы проиграли» / «боевая ничья» / «просрано всеми»), а во-вторых, чтобы по транскрипту тоже ориентироваться.
Метода объединения субъективных оценок разных людей я пока не придумал, но сами оценки уже вроде вполне можно получать ^^
А пока правила такие: – загрузить файл «cmp» через нижнюю форму на страничке. – щёлкать в таблице по лучшим фразам из средних двух столбцов (анонимы слева, мы справа) – если переводы одинаково хороши, то отметить крайний правый столбец (транскрипт Хасбро) – если переводы безнадёжно плохи – то самый левый (транскрипт анонимов). – не нужно отмечать каждую-каждую строку, надо следить за разбиением. Если разбиение неэквивалентно (всё из-за транскрипта Хасбро, он какой-то кривой местами) – то оставлять некоторые строчки жёлтыми, нетронутыми. Обычно, когда в одной клетке фраза целиком, а в следующую почему-то выпала её часть – то оценивать вторую не следует. – сохранить результат!
Моё субъективное сравнение: http://klimaleksus.narod.ru/Files/D/s6e14.zip – открыть страничку, загрузить в неё файл через нижнюю форму выбора. Результат: / 6 / 60 / 60 / 182 / – побед и поражений, к сожалению, поровну. И это без учёта аж шести полностью провальных реплик, когда наш вариант, как выяснилось, неправильно интерпретировал оригинальный текст. Однако, я не засчитывал отдельно «жёстко надрали», когда вражеский вариант ударил в молоко (хотя по идее, под это можно забрать самый правый столбец, тогда отмечая равенство просто отсутствием выбора).
А ещё, я старался считать объективно. Например, рассматривал каждую реплику в контексте своих соседних, то есть не пытался собрать из двух потоков один хороший, а просто оценивал, насколько хорошо данная фраза вписывается в своё окружение. Поэтому, например, одна удачная реплика не заставит несколько следующих перетянуть чашу весов, потому что да, продолжение подходит к ней замечательно, но ведь и не лучше же, чем в другом столбце, соответствующее продолжение подходило к уже шутке похуже.
Если реплики, в принципе, равнозначны, то я не старался во что бы то ни стало отделить лучшую. Также, если они доносят мысль абсолютно разными путями (что уже делает их несравнимыми), но при этом каждый из них выглядит вполне хорошим, то это ничья. Однако если один из конкурирующих вариантов содержит хотя бы малый оттенок (может даже частица «-то» и есть единственное их различие) того, что присутствовало в исходной фразе, а другой вариант – нет, то это победа.
Такие общие штуки, как «go-go-go» или тот Рарькин болт, я вообще прямо не оценивал – можно считать это просто разным стилем, как например перевод имён и названий. И следовательно, все зависимые фразы рассматривались в своём контексте. И когда выигрывает одна, то это не значит, что в другом переводе «лучше бы чтобы была она» – а скорее сама конструкция, доносящая мысль лучшим способом, но уже со своей точки зрения.
Znaczek #5: Тута я скопипастил все свои обсуждения ещё онлайновой версии пада для TDT. Опять же, всё без разделителей между разными комментариями.
Уф.
Я-то думал, сейчас для пада все хоть сколько-нибудь полезные плагины установлю, базу данных с репликацией зафигачу, и уже можно юзать! Оказалось, что плагины тупо конфликтуют друг с другом, и после установки второго десятка, ядро самого пада упало и больше не запускалось.
Пришлось откатывать. И откатывать… Даже в полудохлом состоянии (в среднем 3/5 попыток входа обламываются, пад вылетает или рушится сервер) эта куча кнопок и панелей перекрывали друг друга, прыгали, ломались…
Я думал, выберу ВСЕ (кроме очевидно не нужных нам) плагины, а потом удалю те, что, оказывается, тоже не полезны. Нифига! Надо переустановить всё с нуля, и ставить их поштучно. Проверяя ПОЛНУЮ работоспособность всех функций пада, и ещё отмечать отдельно для себя, какие плагины и в какой последовательности я ставил.
Не, это всё потому, что их там КУЧА. Плюс, функционал некоторых дублируется, и было слишком наивно полагать, что такое не сконфликтует друг с другом…
Ладно. Зато из хорошего, что я нашёл: – поддержка тегов sub/sup, которые можно переопределить для сокрытия текста, вместо зачёркивания. – якорные ссылки типа [[так]], как у Свимика. – потенциальная возможность загружать файлы (проверить не мог, то ли не встала, то ли сломалась) – отображение авторов в паде (видимо тоже маркерами) – возможность поиска по истории на временной шкале, где будут подсвечены места, где есть заданное слово. Также, виден момент, когда его уже удалили.
И что неплохо бы найти: – разделение пада на «шапку» и «тело» с независимой нумерацией, тоже как у Свимика. – возможность смотреть лог сервера типа как чат, в котором бы показывались события редактирования. Он бы позволил узнать, кто произвёл удаление чего-то.
Ещё из хорошего: – Есть плагин с отличной палитрой! Осталось её настроить. – Можно менять цвета текста, как один из видов форматирования (то есть аналогия – «жирный» и «красный»), допись внутрь не теряет цвет. Список цветов настрою. – Метки пользователей, они показывают точное положение курсора ввода, но кратковременно. Надо изменить, чтобы на строке тоже оставалась постоянная метка. Ещё есть «слежение» за участником. – Два плагина, показывающих авторство при наведении на текст. Один делает это красиво и с задержкой, но не понимает цвета уже вышедших. Другой – показывает всех стандартными всплывающими подсказками, но не обновляется при изменении имён и не отключается кнопкой… – Есть возможность вставлять картинки прямо в пад! Вот прям скопировать картинку – и вставить её. Или можно ввести ссылку, картинка скачается, и её можно будет «оторвать» от ссылки. – Заголовки и горизонтальные линии, но там ещё пообрезать кое-то надо. – Меняющийся размер чата, прям как на Пиратенпаде. Но можно ли раздвигать список пользователей, я пока не понял. – Подсветка синтаксиса, которую можно настроить так, чтобы она, к примеру, всякие «Twilight:» – заголовки реплик серыми делала, например. Я всё хотел прикрутить такое, чтобы текст от начала английской реплики до первой русской буквы был бы на слегка сером фоне, но мне не удалось пока; либо это ценой предыдущего, там регулярки конфликтуют. Или два «языка» делать. – Оу, пад стал русским! А я лишь «en-gb» на «ru-ru» поменял…
Из неприятного: – Ссылки на [[текст]] не работают, или требуют ещё какого-то плагина. – Как сделать кликабельные номера строчек, чтобы переходить по ним – не понял, хотя аж два плагина предлагали возможность перехода к строкам по якорю в ссылке. – Как запаролить пад, я пока не разобрался. В наскок прошлый раз же всё поломалось, а там есть порядка 3-5 плагинов, предлагающих эту возможность. – Пад часто «не прогружается» с какой-то страшной ошибкой (поменять бы её текст…), но есть решение: зажать «Ctrl+R» или «F5», чтобы обно-обно-обно-обновить страницу. – Картинки на кнопках иногда не отображаются в Firefox. – Возможность получать информацию о том, кто удалил кусок текста, не предоставляется никаким плагином, вроде бы. И пока не понятно, как сделать её (знали бы вы, что там за 1+*b+0-f/5* в базе храниться…), но как-то же можно. – Закладок на строки нет. А штука ведь была полезная, надо из моего браузерного плагина вытащить.
Я понял, что проще вытаскивать логику плагинов, перерабатывать её, и вставлять в СВОЙ. Причём, в единственный. Ну или хотя бы группировать по общим свойствам, чтобы не было, что, грубо говоря, для жирного текста один плагин, а для курсива – другой. Более того, они ещё и неписаны неоптимально. От большого количества всё лагает. И сам интерфейс ядра пада какой-то хромой.
Короче, что я подумал: зачем наворачивать его до полного блеска, то самой последней фишечки?
Ведь быть может, мы завтра попробуем его, и окажется, что он либо рушится, либо никого не устраивает, либо в нём невозможно работать…
Я пока базовый функционал отладил (может сейчас ещё кликабельными номера строчек сделаю…), давайте хотя бы так его проверим.
Без внешней базы данных, без репликации на другой хост (всё это нужно серьёзно отлаживать) – всё будет хостить кто-то на своей машине. Все пады сохраняются в один файлик «черновой базы», и тут даже паролить не нужно – можно выбрать весьма рандомный порт, и никто просто не будет знать, как достучаться до пада.
На всякий случай, можно сделать один и заблокировать создание других падов.
…что за отстой, почему в новом паде нельзя отменять выбеливание!? «Error: Can't apply USER_CHANGES, because Trying to submit changes as another author in changeset …».
Более того, случайное нажатие ЛЮБЫМ участником комбинации Ctrl+Shift+C – очищает все авторские цвета документа сходу, а следующее же за ним Ctrl+Z – не срабатывает и выбрасывает из пада, потому что сервер думает, что клиент пытается что-то чужими цветами писать.
Я манал. Всё, я пошёл системные файлы ядра корректировать…
Странно, на этой строке стоит комментарий: // the empty author is used in the clearAuthorship functionality so this should be the only exception if('author' == …
– значит что-то другое вызывает глюк. Пофиг, закомменчу проверку.
Сделано в моих плагинах: • форматирование текста + смена шрифта, его размера и цвета – сохраняется как атрибут (т.е. применяется к части текста), глобально. • Масштаб текста всего пада, локальный для каждого. • Горячие клавиши: Ctrl+S – зачеркнуть, Ctrl+D – выбелить, Ctrl+E – скрыть (ниже); блокировка Ctrl+Q и Ctrl+W, а также подтверждение на F5. • «@», показывающая что изменения сохранились. Должны быть зелёная/синяя, но будет, видимо, голубая/красная. • Сокрытие текста по кнопочке «H» на панели, или Ctrl+E. Работает так: если выделен текст, то он будет свёрнут в одну пунктирную «|», это глобально для всех. Если текст не выделен, то команда развернёт (или свернёт обратно) ЛОКАЛЬНО весь скрытый текст в строке с курсором, он будет взят в пунктирную рамочку. Для глобального снятие скрытия, можно выделить «|» с мясом, и нажать Ctrl+E несколько раз: сначала все свернётся в одну, затем локально раскроется но останется выделенным, и наконец – рамочка и атрибут скрытия будут сняты (это проще, чем я описал).
• Разбиение пада на секции, ОЧЕНЬ полезная функция. Секцию начинает строка «==Х», где вместо Х – одна русская заглавная буква, или пробел. Например: ==Ш== == == // Основной раздел ==П== // песня – тогда все строки, начиная с этой, будут перенумерованы в Ш1 Ш2 … 1 2 … П1 П2 …
– пробел вместо буквы обозначает «обычную» нумерацию без префикса. Естественно, добавление новых строчек в разные секции не собьёт их новую нумерацию (номера обновятся через секунду после изменения). Технически, названия секций могу совпасть, но это нежелательно. Отсюда вытекает: • Быстрый прыжок на строку. Работает и в чате, и в паде – просто двойной щелчок по «номеру» строки в тексте (число N, либо буква+число XN). Номера никак не выделяются ни в паде, ни в чате, но двойной клик по ним сработает. Разумеется, с учётом секций (обязательно ставьте именно русскую букву перед номером). Технически, прыжок на самую первую строку невозможен.
Включённые плагины, но я внёс в них изменения:
• Палитра. Я вручную выбрал оттенки и их параметры яркости. Хотя, исходный колор-пикер на любой цвет я убирать не стал, так что всегда можно взять свой цвет. • Вставка картинок в пад. Я наспех добавил туда ещё одну опцию размера (там было 100%, 50%, 25% от ширины пада) – исходный размер картинки. Кстати, изменения этих размеров (нажатия на квадратики внизу) – глобальны для всех! • Изменяемый размер чата. Он глючный, короче: чтобы раздвинуть его, возьмите мышью за полоску, потом поднимите курсор наверх на панель (а не на пад), и тащите там. По паду на тащится. И совсем свернуть его тоже нельзя.
Плагины как есть: • звёздочка в заголовке, когда пад был отредактирован кем-то во время того, как окно браузера не было на переднем плане. Потом туда надо и кол-во непрочитанных в чате выводитью. • Проверка орфографии. Кстати, отключается в настройках на панели. • Локальная отмена переноса текста по словам. Не отлаживал, меняется тоже в панели настроек.
Глюки пада: • Грёбанная панель сверху!! У меня иконки на ней постоянно пропадают! Помогает Ctrl+колёсико (масштаб), сворачивание и разворачивание окна, открытие других вкладок. В общем, бред какой-то, я манал. Потом придумаю, как переделать… • Кнопка «сохранить ревизию», я хотел её в панель настроек убрать, но уф, короче, просто забейте на неё, она бесполезна. • Таймслайдер имеет какой-то отвратительный интерфейс, но функционал норм. • Кстати, плагин «поиска текста в истории» при работе нагружает ЦП сервера на 100%, так что я его вырубил пока. • Если увидите страшную чёрно-красную ошибку – удержите Ctrl+F5, чтобы хорошенько обновить вкладку.
Планы: • Закладки на строки, как в моём том плагине. С учётом секций. • Метки, кто где находится, и возможность узнать автора любого текста. На самом деле я оставил выключенными несколько плагинов, их потом можно будет опробовать. Но они могут затормозить пад. • Сервер-лог, о том, кто где сколько, когда и чего сделал (добавил или удалил, и примерно на какой строке). Я уже придумал, как, но опять-таки требует аккуратной отладки, пока рисковать не стал. • Может быть: автоматическое выделение другим цветом английского текста в строчках, глобальные динамические закладки, или ещё что-нибудь прикольное.
Установка: 1) Распаковать архив в корень диска. Имя папки должно быть коротким, например C:\ep\ или D:\tdtpad\ 2) Открыть и отредактировать «settings.json». Там сверху вписать свой ПУБЛИЧНЫ адрес IP, на который нужно будет всем заходить. Номер порта тоже можно поменять. 3) Запустить «START.BAT». Это откроет большое окно лога сервера. (А программа «nircmd.exe» нужна для повышения его приоритета, и чтобы если вдруг сервер упадёт – был звуковой сигнал и уведомление). 4) Зайти на http://IP:PORT/ и создать новый пад. (делайте сразу два: один основной, а второй для тестирования). 5) Чтобы запретить создание новых падов, закройте сервер (это огромное консоль – сам сервер и есть, его закрытие останавливает пад), и раскомментируйте «"editOnly" : true,» в «settings.json». Перезапустите «START.BAT». 6) Пока плевать на «пользователей» (я отключил администрирование), и на «текст по умолчанию» – легче просто в паде сразу текст изменить.
Я ещё и кроссбраузерность потом настраивал! И парсер чата, чтобы найденные номера строк ссылки не пороли…
Но мне кажется, он должен запуститься без проблем с первой же попытки.
Вот скрипт, чтобы подгрузить все сообщения в чате любого пада (например, если нужно что-то найти по тексту в истории чата):
– он просто жмёт по кнопке автоматически, как очередная пачка сообщений прогрузилась. Для отмены-остановки – щёлкните в чат с зажатым Alt. (Ещё нужно это сделать после того, как все загрузятся.) Остановить можно в любой момент, а чтобы продолжить – просто выполните скрипт ещё раз.
Запуск, естественно – вставить в консоль браузера (Ctrl+Shift+K/J)
Блин, это правда, что если в паде выделить весь текст и удалить его, а потом отменить удаление – то весь текст для всех остальных будет иметь цвет того, кто удалял его? То есть он сам увидит, будто все цвета остались какими были, но все остальные – увидят лишь его цвет? (то есть нельзя отменить удаление всего текста так, чтобы не присвоить его потом себе)
А то я тут пытаюсь придумать, как сделать так, чтобы по Ctrl+С, Ctrl+V из одного пада в другой все цвета авторов сохранились. Сама авторская система, видимо, дико повязана на том, что нельзя писать чужим цветом. На каком-то этапе предлагаемый цвет меняется на фактический цвет автора.
*прошло 40 минут безуспешный попыток найти нужный кусок кода*
СУКА! Вот оно: («changesettracker.js»)
// Sanitize authorship // We need to replace all author attribs with thisSession.author, in case they copy/pasted or otherwise inserted other peoples changes … (далее нехилая функция размером в два экрана)
Закомментировал.
Теперь вставлять текст можно прямо с чужими цветами, и норм.
Правда, простое копирование тоже сохраняет цвет скопированного. Видимо, нужна будет кнопка не только «выбелить», но и «присвоить себе», чтобы окрасить кусок текста своим цветом.
А ещё во всем этом мало толку, если нельзя «входить под другим автором», то есть выбирать свой идентификатор (типа «a.Xv8BLjRJhw0fr9qF»), что всё равно не позволит задавать цвет тем, кого в паде не было.
Видимо, на этот счёт нужно ещё что-то придумывать: адекватный способ, как во-первых, импортировать HTML вместе со всеми авторами и их цветами (причём чтобы эти авторы-призраки формально стали действующими), а во вторых, иметь возможность менять цвета вышедшим пользователям.
Кстати, я нашёл по крайней мере одну недоработку в ядре лайта, которую даже стоит на гитхаб им запостить. Но я сам не хочу, там с гитом разбираться, форкать, пуллреквестить…
Клиент, отправивший чейнджсет, получает обратно лишь «true», в то время как все остальные – полную информацию и результат чейндсета.
Если я хочу сделать хук на клиенте, чтобы отслеживать все приходящий чейнджсеты – я эффективно пропускаю собственные… (нет, при отправке ловить – не вариант, там столько всего может случиться).
О-о, я знаю, что такое чейнджсет)) А выглядит он примерно вот так: «Z:6v>4|7=6t*2+4$Хех.» – тут кто-то написал «хех»
Оказывается, там решается такая нехилая математическая задача, о том как множество символов, называемое документом, путём некоммутативного умножения на специальную величину, называемую набором изменений, переводится в некий другой документ. Предлагает алгоритм как сделать так, чтобы два разных пользователя, изменившие документ одновременно, получили адекватный и ОДИНАКОВЫЙ результат в ответ на свои действия.
То есть клиенту не нужно ждать, когда сервер покажется ему, что произойдёт – потому что рассчёт гарантирует, что и у клиента, и у сервера, и у других – даст одинаоквый результат независимо от того, в какой последовательности обрабатывать данные.
(Но в самом алгоритме я конечно не разбирался. Но это блин, круто!)
Давайте гипотетически представим, что я поставил себя в рамки необходимости адаптировать под свои нужны некий open-source проект, славящийся своей «мелкая фича – стабильный релиз» системой, и кучей плагинов (которые при подходе «сначала включу все, а потом удалю ненужные» конфликтуют до умирания всего сервера, вынуждая с нуля добавлять поштучно со строгим контролем за логами), разработанными кучей людей под кучей лицензий, и всё это настолько повязано на git-подходе, что тупо багфиксить ./*/node_modules/*/node_modules/*/somefile.js и хардкодно прописывать туда нужные мне флаги вручную уж как-то совсем-совсем некрасиво и непортабильно получится, а на полном серьёзе делать репозитории, форки и бранчи – это прям какая-то новая ниша для меня, нырять в которую я сейчас совсем не готов.
– эта байда, кажется, отправляет тому клиенту, кто запостил изменения, сообщение «ACCEPT_COMMIT», а всем остальным клиентам – «NEW_CHANGES». Проблема в том, что я хочу сделать плагин, который слушает эти сообщения, и выводит (на экран или куда либо) некий лог, в котором бы в читабельном формате было понятно, какой участник внёс примерно (хотя бы, было ли это добавление или удаление) какие изменения («changeset»), и примерно где (его текущую позицию «на какой строке», кажется, отсюда не достать, но я предполагаю, что допустим, будет активен другой уже существующий плагин, постоянно постящий «CUSTOM» сообщения с координатами курсора). Я, по-видимому, упираюсь в то, что клиент не слышит своих же «NEW_CHANGES», и они не будут отображены в его локальном логе, а я по меньшей мере хочу, чтобы логи у всех были одинаковые. Можно конечно отловить момент отправки changeset’а на сервер, но это опять искать это в файлах и какие-то хаки прописывать, ещё и обработчик усложняется. К тому же, «отправил» ещё не значит, что «отправилось». Хотелось бы получить сообщение «ACCEPT_COMMIT», в котором были бы все те же данные, что и в «NEW_CHANGES». И более того, раз тут простой author==me, что делает фикс элементарным:
Здесь для клиента-коммитера меняется «NEW_CHANGES» на «ACCEPT_COMMIT», а все сопутствующие остаются. По идее, на работу ВСЕГО остального кода, это не должно повлиять, ведь даже если где-то слушается «ACCEPT_COMMIT», то, раз в нём ничего больше не ожидается, то важен сам факт; а лишние данные в объекте будут просто проигнорированы. Хотя и создадут некую _мизерную_ нагрузку на сервер/канал передачи, но учитывать такое – полный бред, особенно если задуматься о том, что похожие сообщения шлёт тот плагин, трассирующий позицию, – при КАЖДОМ щелчке мышью / движению текстового курсора от КАЖДОГО клиента, а сервер вещает это при КАЖДОМ щелчке мышью / движению текстового курсора от КАЖДОГО клиента, а сервер вещает это КАЖДОМУ клиенту (а при коммитах и того дважды), как раз включая себя!
Если поступить ещё разумнее, то с учётом имеющегося в файле var settings = require('../utils/Settings'); – моё «false» и второе ?: условие можно дополнить на нечто вроде «settings.enableSendChangesInCommit», отсутсвующее в конфиге по умолчанию, и вообще не приводящее к изменению работы приложения, без присвоения этой настройки.
«The main development happens on Github. To contribute, fork the main repo, branch off a feature branch from develop, make your changes and commit them, push to your fork and submit a pull request for ether/develop.»
– серьёзно? Делать это? А вдруг эта фича у них уже запланирована?
Или же: «If you'd like to help, get in touch!» – ссылка ведёт на mailing-list и ещё куда-то. Может об этом просто написать кому-то?
Либо же – тупо в коде поменять, и положить на всю эту опенсорсную инфраструктуру?..
1) Я не меняю тип сообщения – следовательно всё остальное будет работать как раньше. 2) Да, клиенту эхнется то, что ему по сути не нужно. Но какие удобства это мне даёт при прослушке входящих сообщений!
Я вот говорю же что хочу – чтобы можно было ТОКЕН выбирать.
Чтобы я мог сделаться «a.aleksusklim___» – и тогда в какой бы пад я не вошёл – я всегда буду я, и любой, ЛЮБОЙ мой текст всегда будет моим, даже если он чёрт побери из прошлогодней истории или скопирован из другого пада.
(ну да, если кто другой впишет этот, публично видимы идентификатор – весь мой текст будет его… Но мне не жалко – в конце концов, это наш ОБЩИЙ текст, просто цвет на нём мой. Для нашего же удобства)
Так вот. Пад сломался от переполнения стека. Причём именно в тот момент, когда я нажал «экспорт в .ertherpad». Сама трёхгиговая база – абсолютно работоспособна, хотя не факт, что она верно сформирована.
Проблема в том, что в .etherpad формате должно быть сохранено всё содержимое пада, и все его ревизии. И этот формат – JSON. Забавно, но я уже упирался в этот баг на Апаче, причём тогда решить его не смог. Сейчас же повезло! Итак, рекурсивная функция заворачивания данных в JSON формат на таком огромном паде привела к переполнению стека на сервере. Причём Node.js сам сообщил об ошибке, потому что не упал, а достиг заданного предела. Однако, под Windows, этот предел нельзя просто так расширить, потому что иначе программа рухнет физически. Лучшее решение – действительно увеличить стек. Стандартный – всего 1Мб, а я теперь увеличил его до 16 Мб (что значит, что по крайней мере на падах, которые не более чем в 30 000 раз больше нашего – можете считать, что это тридцать тысяч часов вместо одного часа стабильной работы – на них переполнений стека возникнуть не должно).
Для этого мне даже не пришлось перекомпилировать из исходников, я нашёл маленькую утилиту, пропачивающую программы – и применил её на «node.exe»: http://klimaleksus.narod.ru/Files/D/stack.rar
Инструкция: – распаковать в папку моего пада (содержимое \bin\ должно пойти в имеющийся \bin\), заменив START.BAT (там лишь один новый параметр —stack-size=15360 – виртуальный лимит на 15 Мб для Node.js) – зайти в \bin\ и запустить «check.bat». Выйдет много инфы (окно можно закрыть или нажат Enter), там должно быть:
100000 size of stack reserve 1000 size of stack commit 100000 size of heap reserve 1000 size of heap commit
(это в шестнадцатеричной системе, если что)
– Теперь надо запустить «patch.bat». Нажать Enter, потому что окно никак не сообщит о том, что всё готово. И снова выполнить «check.bat», где на этот раз будет:
1000000 size of stack reserve 10000 size of stack commit 100000 size of heap reserve 1000 size of heap commit
А теперь я вот думаю, с чего база-то так разрослась? Подозреваю что из-за плагина «вставка картинок в пад». Не то что бы два моих вставленных 1024*768 скриншота очень много весили… но если в базу кладётся каждый раз полная копия текста пада в каждой ревизии, создающейся чуть ли не каждым нажатием очередной клавиши каждым участником? Хотя, я пока так и не понял, что конкретно ложится в базу. Вытащить бы как-то количественно-качественную информацию о том, чем всё-таки забит файл – текстом или же base64 картинками.
И я проведу эксперимент, специально вставляя в пад картинки и замеряя удар по объёму базы (думаю, для MySQL это в перспективе, также актуально), что поставит под вопрос необходимость в таком неэффективном плагине, хотя и удобном.
Надо, чтобы эти картинки не как текст пада хранились, а просто на сервер загружались как файлы. А не в базу. Было бы норм.
Я там уже и с репликацией почти разобрался, но я ЧЕТЫРЕ раза свой финальный вариант запускал с нуля – и он ломался, и снова танцы с бубном.
Последний раз была проблема, что какая-то команда выполняется на Win7, и не пашет на XP, но я не понял, какая. А когда подгоняю под XP и дерзко тесчу на семёрке – опять баги лезут…
Так что я пока ещё потещу. Там ж ещё сам MySQL выкладывать, лучше пусть сразу всё будет норм.
Так вот. Я тут довольно долго размышлял над тем, как можно устроить в новом паде защиту от подмены персональностей участников, и пришёл к выводу, что если кто-то САМ захочет, чтобы его персональность была подменена – то с этим ничего нельзя сделать. Это ж как аналоговая дыра (см. википедию), а именно: если кто-то захочет, чтобы из-под его аккаунта действовал другой человек – он всегда может предоставить ему удалённый доступ к своей машине сторонними средствами, не говоря уже о возможности физически передать свой компьютер во временное пользование кому угодно. И тогда никто на свете не сможет доказать, кто в паде: тот, кто должен быть, или тот, кому тот захотел дать доступ.
Однако, защитить честного пользователя от попытки подмены его ник-нейма в паде злоумышленником – вполне возможно. Первоначально я рассмотрел стратегию доступа с «инвайтами». Грубо говоря, это специальные одноразовые пароли, которые генерируются для всех потенциальных пользователей пада. Такой инвайт хранит «второе имя» (будем так называть то, что позволит отличать одного законного пользователя от другого – то есть не видимый ник-нейм, но и не безликий ключ сессии или идентификатор автора – цвет) внутри себя. Это значит, что первый зашедший по данному инвайту – получает сессию, связанную с конкретным вторым именем. Два раза зайти по одному ивайту невозможно. В принципе, пользователи сами, опционально, могут генерировать новые инвайты (в том числе запасные для себя), и раздавать из другим – но тогда внутри инвайтов запоминается история, кто и кому предоставил доступ. От, грубо говоря, расшариваний пароля, это не спасёт, но зато администратор сможет проследить цепочку инвайтов от своего доверенного лица до ворвавшегося в пад вандала. Либо, если инвайты сможет создавать только администратор – то доступа в пад не будет ну у кого свыше тех, кто получил инвайт, что, с другой стороны, затрудняет сам процесс приглашения участников в пад: нельзя будет публиковать общую ссылку, по которой все смогли бы зайти. Ему придётся давать каждому свою ссылку, причём лично и секретно.
Такой вариант в наших условиях мне показался неудобным. Зато вторая идея получше: система закрытых и открытых ключей, которые будут создаваться потенциальными участниками, и вноситься в конфигурацию пада администратором. Для тех кто не знает: система PGP ассиметричного RSA шифрования – это когда клиент может сгенерировать пару ключей (текстовых строк или маленьких файлов), один из которых, закрытый, он должен тайно хранить у себя; а второй, открытый – расшарить остальным, и в особенности, серверу/администратору.
Сервер может зашифровать отправляемую информацию на открытом ключе, а расшифровать её сможет только тот, у кого есть соответствующий закрытый ключ (то есть получить информацию после такого шифрования не способен даже сам сервер). Более того, схема позволяет клиенту зашифровать что-нибудь на своём закрытом ключе, и тогда расшифровать смогут все остальные, но именно при помощи его именного открытого ключа, что является гарантией того, что информацию послал именно он.
Итак, применительно к паду, протокол работает так. В админке пада есть страничка, куда можно добавить пары «второе имя» – «открытый ключ». При обычном входе в пад, клиентский интерфейс предлагает либо сгенерировать новый набор ключей, любо открыть/вставить имеющийся закрытый ключ. Участники через этот интерфейс создают пару ключей, и отправляют администратору свой логин (вернее, второе имя) и открытый ключ. Тот вносит все ключи на сервер.
Теперь, при входе в пад и выборе закрытого ключа, происходит следующее: – Все отправляемые сообщения (кроме приветствия, либо же в каждом будет пересылаться копия «второго имени», чтобы сервер знал, чьим ключом оперировать) от клиента серверу шифруются на его закрытом ключе. В приветствии посылается второе имя, которое сервер кладёт в сессию. – Сервер дешифрует входящие сообщения открытым ключом заявленного пользователя. Но если у него нет такого ключа, или он не подошёл – сообщения игнорируются и остаются без ответа. – Все отправляемые клиентам сообщения (именно ajax-запросы, а не сами отдаваемые .html странички или .css/.js статику – все это сервится всем желающим без разбора) шифруются на открытом ключе того, кому они предназначаются. – Клиенты расшифровывают приходящие сообщения на имеющемся закрытом ключе.
Всё это, без дополнительных систем токенов или проверок, гарантирует, что никто не сможет подменить собой никого другого участника без его согласия (что выразилось бы в пересылке ему своего закрытого ключа). Реализуется довольно просто – изменением части кода ядра пада, отвечающей за непосредственную пересылку и приём сообщений. Как я понял, там можно найти конкретные точки входа и выхода, именно на которых будет достаточно ввести шифрование.
Основная сложность тут, скорее, в самом интерфейсе удобного выбора и добавления ключей. Которые, кстати, не должны храниться в базе данных, а просто оставаться на сервере как файлы.
Я даже нашёл модуль для Node.js, со всеми необходимыми функциями – «node-rsa». Но к сожалению, я не смог заставить его работать в браузере, хотя технически это возможно (через некий «browserify», который не то уже есть в паде, не то отдельно ставится как приложение, но я манал этот линуксовый «npm install», к которому сводятся все советы по использованию…)
О, а ведь я тут действительно исследовал, мог ли плагин вставки картинок в пад быть причиной того, что наша база данных вдруг стала неоправданно большого размера. Итак, я создал пустой пад, и сделал PrintScreen и несколько Ctrl+V подряд. Штук шесть. После чего попробовал пописать. Ну вроде, ничего: база росла на глазах, но всего лишь по полмегабайта за коммит. Мало. Тогда я вставил туда тот же самый скриншот ещё раз десять или пятнадцать, а затем добавил снизу содержимое любого нашего типового пада. Правда у меня браузер так подвис, что сервер его выкинул. Ну, я перезашёл…
О-о-о, а потом моя бедная мозиллка-тормозилка в течение сорока минут пыталась прогрузить содержимое пада, медленно наращивая память (единственная вкладка) с двухсот до шестисот мегабайт. Я так и не дождался конца, сбросил Диспетчером. Не было ни уведомлений, мол, скрипт завис, ни возможности хоть на что-то нажать в интерфейсе браузера. Труп трупом.
Итого, плагин вставки картинок в пад – зло. Выглядит клёво, но взамен душу заберёт. Уж лучше вон тот, который локально по ссылкам на изображения эти самые изображения в паде и вырисовывает. А ещё круче, если его можно объединить с каким-нибудь механизмом, загружающим файлы на сам сервер – тогда даже ничего изобретать на надо – загрузил картинку, вставил ссылку.
Это с расчетом, что все пойдёт на ОК? – да не пойдёт оно, я уже пять раз так думал. Вот всё идеально настраивал, ставил на новый комп – и не шло. А там правил. Правил на мастере, правил на реплике.
Потом путался, где какие изменения. Или менял что-то, что по идее не должно всё испорить (вроде имени какого-нить файла), а потом на генеральной репетиции – бах, на последнем этапе ошибка именно в его названии, которое я забыл куда-то прописать.
Гуглинг ошибок. Забано, например, было видеть ответом (причём правильным), что «не найден индекс первого бинлога мастера» означает всего лишь, что репликация была подцеплена не к тому серверу (например, к своему же собственному!)
Всё же, чем больше прог что-то меняют в файлах, тем сложнее потом вмешиваться при надобности.
Например у меня сейчас root-пароль генерируется рандомом. Но он может не вступить в силу почему-то, после выполнения скрипта. А почему? А хрен знает. Но в процесс уже не вмешаться, там всё на автоматике. Пришлось часть работы оставить пользователю (например, закрыть сам MySQL, когда то будет нормально открыт, ибо скрипт у меня не то что узнать об ошибках не может, он вообще состояние сервера не в силах понять!..) but nobody came
Сообщение отредактировал aleksusklim - Воскресенье, 05.11.2017, 17:39
Znaczek #6: Копипащу анонс и полную справку (потому что отдельного описания не, но и несмотря на то, что говорят, что по ней тоже всё равно непонятно, что именно делает эта программа) утилитки для упорядочивания кучи файлов субтитров в списки по персонажам с возможностью воспроизвести любую реплику с высокой вероятностью успеха.
http://klimaleksus.narod.ru/Files/4/AssEasyQuote1V0.rar С пользой провёл разве что быстрое пробное тестирование: http://klimaleksus.narod.ru/Files/T/aeq_test.mp3 (ответ кроется в вопросе, насколько быстро мне удалось такое смонтировать) – сделано на скорость, аж путём глупого внешнего перехвата выходящего потока из плеера, запускаемого моей же программой. Не знаю, получилось ли сделать отрывок более-менее связным или логичным, но это был просто тест потенциальных возможностей.
Учитывая, что у меня не было ни всех сезонов, ни высококачественных источников, ни даже файлов оригинальных субтитров (подбирал по русским). На фон взял первую попавшуюся, мне в таких ситуациях, как правило, всегда везёт.
Данная программа предназначена для пересортировки текста в нескольких файлах субтитров, чтобы упорядочить их по персонажам. Работает это следующим образом: – Программа считывает группу .ass файлов. – Каждая фраза извлекается, сохраняя имя персонажа (наименование стиля) и время. – Создаются документы-списки на каждого персонажа, в которые выгружаются фразы. – Реплики снабжаются абстрактными порядковыми номерами. – Сохраняется общий индексный файл, глобально закрепляющий за номерами реплик времена начала и конца, а также название исходного .ass
Далее программу можно использовать для выборочного воспроизведения реплик из оригинальных видеофайлов. Для этого: – Программа запускается фоновым процессом в трее, и предварительно сканирует папку с видеофайлами, запоминая их имена. – Далее она ждёт горячей клавиши, и по нажатию Ctrl+Alt+Space программа получает содержимое буфера обмена, ожидая обнаружить там номер некоторой строки (он должен быть скопирован вручную) – Если найденный номер соответствует имеющейся в индексном документе, и программа знает местонахождение видео (или аудио) с тем же именем – запускается фоновое воспроизведение через «Media Player Classic», поддерживающий начальное смещение. – Программа вычисляет оставшееся время, и после подаёт сигнал плееру об остановке воспроизведения. Возможны задержки во времени из-за загруженности процессора или медлительности чтения большого файла с диска.
Инструкция по запуску: – Соберите все свои видеофайлы в какую-нибудь папку. Они могут располагаться в разных подпапках внутри неё, но желательно, чтобы там нигде не было множества других файлов, не относящихся к видео или субтитрам. – Соберите все субтитры вместе, также можно в подпапках. Если у вас субтитры уже лежат рядом с видео, и вы хотите использовать именно их, то можно оставить их там (папка просто будет той же); если же рядом с видеофайлами находятся какие-то другие субтитры, то соберите нужные отдельно. – Убедитесь, что имена целевых субтитров (без расширения) попарно соответствуют видеофайлам; все файлы должны иметь разные имена, поскольку сравнение происходит без учёта пути. Желательно, чтобы использовались только латинские буквы и цифры, потому что всё остальное заменяется символом подчёркивания при сравнениях. Однако, если имена файлов отличаются именно латиницей и цифрами, то проблем не возникнет даже когда в именах присутствуют русские названия. – Запустите «AssEasyQuote1V0.exe» двойным щелчком. Перейдите в корневую папку, где лежат целевые субтитры – позже поиск будет произведён в ней и подпапках. Диалог сделан как «сохранение файла», однако туда ничего сохранено не будет (просто так было удобнее папку выбирать, потому что есть куда путь вставлять), нужно лишь в правильной папке формально «сохранить» под любым именем, или дважды щёлкнуть по любому файлу в ней. – Теперь выберите ту папку, из которой нужно брать видео. Это может быть та же самая папка, потому что в дальнейшем программа сумеет различить .ass субтитры от всего остального. – Наконец, настоящий диалог сохранения! Выбранное имя файла будет итоговым .ini списком соответствия номеров реплик. Рядом с ним появятся .txt файлы, с именами персонажей и их текстами. – Далее программа в трее сообщит о прогрессе обработки, и закроется. Можете зайти в целевую папку и посмотреть на извлечённые строчки.
Для прослушивания реплик: – Перетащить в Проводнике ваш созданный индексный .ini файл на «AssEasyQuote1V0.exe». Он будет прочитан, а указанная в нём папка видеофайлов – просканирована. Если программа уже была запущена, то прошлая её копия будет насильно закрыта. А чтобы не тащить индекс куда-то далеко, можете заранее переместить его в папку с программой (ему не нужны извлечённые реплики в соседних текстовых файлах персонажей – это вам они нужны). – Программа сообщит в трее, что готова. Теперь откройте любой документ с персонажа в любом текстовом редакторе. Скопируйте интересующую вас строку, или хотя бы её порядковый номер (это шестнадцатеричное число, а захваченные пробельные символы игнорируются). Нажмите Ctrl+Alt+Пробел. – В трее будет указано имя файла и целевое время этой фразы. Должен запуститься свёрнутый плеер, в котором должно запуститься соответствующее видео с правильного места, и по окончанию реплики остановиться. Если окно с плеером уже открыто, то оно и перехватит команду на воспроизведение. – Продолжайте слушать фразы, сколько вам нужно. Для выхода из программы, нажмите правой кнопкой на иконку в трее, и щёлкните «Exit». Если плеер по какой-то причине перестал воспроизводить, нажмите Ctrl+Alt+Space дважды – процесс плеера будет сброшен, и повторный вызов должен пройти хорошо. Чтобы воспроизведение не закончилось сразу после конца реплики, можете щёлкнуть по иконке в трее левой кнопкой мыши, остановив работу программы. Для возобновления, снимите галочку с «Script Paused» в контекстном меню иконки; возможно, понадобится закрыть плеер. – Реплики во фразах персонажей отделяются одной пустой строкой, если не следуют непосредственно друг за другом в исходных субтитрах; и двумя пустыми строками, если вообще принадлежат разным файлам. При создании файлов, если документ с таким персонажем уже существует, то он будет заменён новым – поэтому лучше всегда создавайте новую папку при выборе места для сохранения индексного файла.
Альтернативный способ обработки файлов: – Для этого нужен «современный» браузер, откройте файл «AssEasyQuote1V0.htm». Этот способ может быть оказаться быстрее предыдущего при очень большом числе субтитров и персонажей. – Сложите все субтитры в одну папку, и заархивируйте её в .zip – Откройте архив интерфейсом на страничке, или перетащите его на элемент загрузки файлов. – Страница, после обработки, вернёт вам некоторый файл. Сохраните его как .zip архив. – Распакуйте полученный файл. Там окажется, в том числе, один .ini файл. – Откройте его текстовым редактором, и вставьте на первую пустую строку полный путь к той папке, которую вы бы выбрали как папку с видеофайлами. – Всё, можете перетащить его на программу и пользоваться как обычно.
А вот ещё этапы разработки и финальная версия скрипта, мониторящего доступность видео на Ютюбе.
Инструкция: 1) Зайти браузером на https://www.youtube.com/oembed (там «Not Found») 2) Открыть консоль браузера (Ctrl+Shift+K/J/C) 3) Вставить туда содержимое текстового файла по первой ссылке.
4) В текстовое поле вставить ссылку на какое-нибудь видео. 5) Нажать Enter или ADD. Добавить ещё несколько видео.
6) Таймер пока одноразовый, без повторной проверки. Кнопка «now» запускает проверку данного, кнопка «DEL» – удаляет строку. 7) Посмотреть результаты работы скрипта – зелёный на хороших видео, красный на плохих. 8) Было бы здорово проверить, что существующее, но удалённое позже видео, при нажатии «now» начинает выдавать красный.
Осталось придумать, какие уведомления выдавать (думаю, что смогу звуком), и выбрать интервал обновления…
Если текущая страница не «youtube.com/oembed», то скрипт либо сам переадресует туда в текущей вкладке (если посчитает её содержимое не важным), либо создаст большую кнопку, по которой можно будет перейти туда в новой вкладке (а если зажать Ctrl при щелчке, то скрипт попытается всё же использовать эту вкладку вместо новой). В любом случае, на целевой странице скрипт нужно будет вставить в консоль ещё раз.
Дальше как обычно, вставлять ссылки в поле (хотя я предпочитаю не ссылки кидать, а только сами идентификаторы видео типа «q7s1B-kd_Uc»). Применять можно по Enter или ADD.
Далее в таблице появится серая строка, и через секунду запросит обновления; но прежде идёт дополнительный запрос на заголовок и картинку для видео (ведь на блокированных видео эта информация не выдаётся).
Обновляемая строка горит либо голубым (если новая, или ещё до этого была зелёной), либо жёлтым (если была красная). Запрос ждёт 20 секунд, и если ответ не пришёл – будут посылаться повторные запросы каждые 20 секунд. Таймер будет идти от нуля в отрицательную сторону.
Пришедший ответ обновляет таймер, устанавливая его на случайное значение от 10 до 35 секунд. Если с видео всё хорошо, то строка станет зелёной.
Если же обнаружен статус "fail", то строка будет красной, и случится уведомление. Таймер, тем не менее, пойдёт как обычно к нулю, и последующий запрос всё равно произойдёт (скрипт же не знает, почему была неудача, может там сервер просто ответил «повторите позже», тем не менее «причина»будет выведена под названием видео). Таким образом, если вставлена некорректная ссылка, то уведомления будут случаться постоянно, примерно каждые 20 секунд.
Чтобы остановить такмер на конкретном видео, есть кнопка «stop» под ним. Она сделает цвет строки белым (если он был зелёным или голубым), либо розовым (если красный или жёлтый). Теперь обновлений не будет, а также кнопки «now» (обновить сейчас) и «DEL» (удалить строку) перестанут работать, пока кнопка «enable» (второе состояние этого «stop») не будет снова нажата.
Уведомление – это во-первых, «Desktop Notifications», и браузер, по идее, должен спросить разрешение у пользователя, при добавлении первого видео в таблицу. Нужно разрешить показ уведомлений! Если браузером поддерживается, то на экране возле трея будет появляться окошечко без иконки, но с идентификатором видео, причиной неудачи, и названием (если поместиться).
Во-вторых, должен быть слышен пронзительный звук сирены ^^. У меня работало во всех браузерах (ну кроме IE, на который я даже не рассчитывал и не пробовал, потому что в нём этот скрипт работать гарантированно не будет). Но возможно, если звука нет, то нужно зайти в настройки браузера и либо «включить звуки на веб-страницах», либо отметить «запускать все плагины» (вместо «по запросу / только важные»).
И в-третьих, заголовок страницы (вкладки окна / иконки панели задач) будет в течение пяти секунд постоянно меняться на всякую всячину.
Вот так, вроде всё. Думаю, что если какое-то видео действительно вдруг оказалось заблокированным – нужно остановить его таймер и принять меры. После того как меры приняты – нажать «enable» и удалить строку.
О, а ещё, строка в таблице может почему-то стать синей. Это произойдёт, если в ответе сервера не найден «status» вообще, или не равен ни «ok», ни «fail». Это ничего не изменит, должно по идее считаться, что ответ не пришёл (перезапрос через 20 секунд), но если происходит регулярно – дайте ссылку на такое видео))
P.S Блин, по-моему, я слишом грубо парсил результаты. Вполне возможно, что видео с названием, включающим символы \, &, <, >, = – может всё поломать. Или нет.
Баг заключался в том, что _возможно_, новое добавленное видео могло сломать проверку всех предыдущих (угораздило же меня написать «if(A[i ].handle=v)…» и не заметить).
Изменения: – теперь промежутки времени (интервал, его рандомная добавка и ожидание ответа сервера) задаются как числа в поля на самой странице. Применяются мгновенно при изменении; если невалидно (интервал меньше 1, добавка меньше 0 или ожидание меньше 2, либо если не число) – подсвечивается розовым. – первый раз картинка на видео прогружается не сразу, а спустя три секунды (чтобы дать возможность маленькой прогрузится, если будет; хотя ждать её нужно было не так…) – таблица формально не пересоздаётся при добавлении очередной строки. – при остановке таймера, его кнопки «now» и «DEL» становятся визуально недоступны. – идентификатор видео во втором столбце теперь является ссылкой, открывающейся в новом окне.
Русифицировал интерфейс. Ну и сделал отлов картиночки именно такой, какой нужно: вначале идёт запрос на картинку высокого качества, которая точно есть (как и название). Далее, если он пришёл – то название выставляется сразу, а ссылка на картинку – запоминается.
При следующем обычном запросе, если вернулось название – то оно заменит имеющееся, но единожды (кстати, название видео у меня по таймеру вообще не обновляется. А надо?) Если пришла ссылка на картинку низкого качества – то вырисовывается она. Если же нет, то берётся сохранённая ссылка на большую если есть.
Когда таймер достигает «0» – на сервер посылается запрос на обновление данных, а таймер продолжает идти «в минус». Состояние запроса никак не отслеживается, то есть верный результат может либо придти, либо нет.
А значит, если ответа нет – через некоторое время нужно повторить посылку запроса (но да, потом могут придти сразу два). Например, если wait = 15, то запрос будет посылаться при таймере, равном 0, -15, -30, -45… (меньше 2 поставить нельзя, потому что от 0 до -1 происходит посылка, и где-то от -1 до -2 – приём, поэтому иначе повторный будет послан слишком рано.)
Я просто подумал, что браузер может кешировать запросы… Теперь всё скачивается через POST (ха, Ютюб не банит за это, как Гугль!), и к запросам добавляется случайное число, чтобы URL был формально каждый раз новый.
Там вроде есть кол-во просмотров, но оно было какое-то не очень адекватное, кажется.
http://klimaleksus.narod.ru/Files/4/ytalert1V5.txt – теперь принимает список ссылок/идентификаторов, разделённых пробелом (вгружаются через секунду по-очереди, но добавляются одновременно). Такой список из текущей таблицы – выводится перед ней (ну чтобы можно было скопировать эту строку, и потом целиком и вставить)
Оу, тут можно ещё кусочек про пад добавить, насчёт переполнения стека – косвенный пример:
А вот что у меня было с Апачем. Забавно, но я делал такой же редактор в реальном времени, как пад – но графический, там можно было одновременно рисовать. Клиент посылал серверу JSON с перемещением курсора, а сервер сохранял его и пересылал всем остальным по их запросу.
Я хотел устроить хотя бы проверку валидности данных, чтобы клиенты не могли заспамить сервер мусором (он ведь вслепую ретранслирует всё другим клиентам), но без полного парсинга JSON для экономии ресурсов.
Но когда клиент водил мышью с особой ревностью, и строка становилась в сотни раз больше – сервер вылетал, перезапускался и соединение разрывалось без получения чего либо (в том числе, адекватной ошибки).
На сайтах пишут, что такие проблемы с preg_match($r,$s) только под Виндой. Потому Апач там по умолчанию скомпилирован с коротким стеком. А ещё рекомендовали перекомпилировать его, поменяв часть рекурсивного кода на линейный… (но тогда мне было вообще не до таких разборок, и мы просто забили на валидацию)
(э, ладно, возьму-ка отсутствующий кусок текста про mysql из предыдущего поста – тот, что в архиве – и плейн-текстом фигану сюда. Ну там, для возможности поиска, тудым-сюдым…)
Поскольку, исправлять баги и плясать с бубном, пока я всё это настраивал, мне приходилось постоянно и многократно – нужно, чтобы пользующиеся моей сборкой чётко понимали, как она работает внутри. Хоть я и свернул всё к простым кликам по .bat файлам, но обязательно что-то пойдёт не так.
Итак, в архиве – куча батников, и папка «MySQLServer5.5» – её переименовывать не надо. В ней есть файл «my.ini» – это основная конфигурация сервера. Нужно выгрузить это в папку, находящуюся (желательно) в корне жёсткого диска, например чтобы существовал путь: D:\TDTPAD_MySQL\MySQLServer5.5\my.ini
Теперь этот путь надо прописать в самой конфигурации дважды, и в моём файле «path.bat»: Там нужен путь типа «@set dir=D:\TDTPAD_MySQL\MySQLServer5.5» А файле конфигурации «my.ini» – два пути, один к этой папке, а второй – к её «DB» подпапке. Причём слеши там требуются прямые. То есть basedir="D:/TDTPAD_MySQL/MySQLServer5.5/" datadir="D:/TDTPAD_MySQL/MySQLServer5.5/DB/"
Все эти пути правильно прописывать ОЧЕНЬ важно. У меня было, что путь «С:\MySQL2\…» был неверен только потому, что там русская «С». Дальше:
Скрипт «MySQL_totalreset.bat» – очищает всё состояние базы данных до заводского, но не трогает конфигурационный файл. При запуске требует подтверждения – нужно ввести английскую букву «y» и нажать Enter. Будет сгенерирован новый локальный root пароль, который запишется в файл «pass.bat» и станет автоматически использоваться в дальнейшем. Откроется окно запущенного сервера с логом работы, если всё в порядке, его нужно закрыть.
Скрипт «MySQL_start.bat» – запускает сервер базы данных. По идее, он работает в фоне и не имеет консольного окна. Больше одного раза сервер запускать нельзя, будут глюки в виде пустых консольных окон или невыполняющихся команд и заблокированных файлов. Если такое случилось – убивайте сервер скриптом «MySQL_kill.bat»
Скрипт «MySQL_stop.bat» – останавливает работающий сервер. Может не сработать, если что-то с root-паролем случилось.
Скрипт «MySQL_kill.bat» – убивает все процессы, имя которых равно «tdtpad_mysqld.exe», это на случай, если предыдущая команда не заставила его остановиться.
Скрипт «MySQL_SHELL.bat» – открывает клиентское окно команд терминала MySQL (это туда надо вводить все те команды, которые можно нагуглить для решения той или иной проблемы), вообще говоря, через него можно сделать что угодно. Но самые главные функции вынесены в отдельные скрипты, а этот потребуется лишь для ручного вмешательства.
Скрипт «MySQL_STATUS.bat» – выводит на экран всю информацию о работе сервера – все процессы с его именем (должен быть один!), его общий статус, текущее состояние репликации и номер бинлога мастера. У меня всё сконфигирировано так, чтобы и мастер и реплика настраивались одинаково, надо просто знать, на что обращать внимание. Если статус вообще не печатается на экран – с сервером что-то не то.
Скрипт «MySQL_debug_log.bat» – запускает сервер (убедитесь, что больше ни одна провисшая копия не активна) в консольном режиме, с выводом лога на экран – сразу покажет примерную причину, почему вдруг сервер не запускается при штатной попытке.
– Ну со всем этим понятно как работать. Сначала «MySQL_totalreset.bat», потом «MySQL_start.bat» и сразу «MySQL_STATUS.bat». Если всё верно – то можно «MySQL_SHELL.bat» попробовать (если есть что писать туда), закрытие или перезапуск – «MySQL_stop.bat» и «MySQL_start.bat» снова. Если пустые окна остаются – то «MySQL_kill.bat», а если всё равно новая копия не поднимается – то «MySQL_debug_log.bat» и вчитываться.
Теперь ближе к паду. Кусочек конфигурации «settings.json» для etherpad-lite:
Так, во-первых, там вверху где «"ip": "127.0.0.1", "port" : 9001,» – айпи, кажется, надо писать «0.0.0.0» – тогда пад будет доступен на машине, независимо от её настоящего адреса (127.0.0.1 ли, 192.168.0.1, или любой внешний). Главное чтобы при подключении порт был тот, который указан тут. Во-вторых, все строки, связанные с «"dbType" : "dirty"» надо закомментировать или удалить.
В-третьих, раскомментировать секцию, связанную с mysql (настройки в ней объединены с dirty для упрощения выбора). У меня там есть нужный кусочек, вот такой:
– здесь, «user» – имя пользователя для базы данных, которому разрешён нужный доступ, это слово «etherpad» (тогда полное его имя – это 'etherpad'@' localhost' ); «port» – на каком порту будет ждать локальная база данных. В MySQL этот порт меняется дважды в конфигурационном файле, там написано «port=3311». Желательно, чтобы на всех используемых хостах этот порт был одинаковым (проблем при согласовании меньше будет). «database» – имя базы данных, куда пад будет всё сохранять. Это строка «ep», далее пойдут несколько работающих с ней скриптов. «password» – пароль для доступа к базе данных серверу пада. Эту строку можно изменить. Я вот думал, как бы сделать рандомную генерацию, но на самом деле этот пароль и никому не нужен, он же локальный и используется автоматически. Можно написать что угодно, просто скопировать в нужные места – и забыть о нём, ведь всё равно кроме как с «localhost» (это в MySQL настроено) никто к базе не присоединится.
Теперь нужно создать базу данных для пада. После запуска сервера, выполнить скрипт «install_db.bat» – это создаст базу данных «ep», и даст к ней доступ по заданному паролю. Чтобы поменять пароль, отредактируйте сам этот скрипт в Блокноте (менять в «identified by 'my-awesome-etherpad-password';»). Также, там разрешается репликация с этого сервера на любой адрес. Пароль репликации – в «identified by 'my-awesome-replication-password';», если его менять – то менять у всех; к тому же, этот пароль внешнего доступа ни на что, кроме самой репликации, и не даёт.
Наконец, пад можно запустить! В его настройках есть закомментированный кусок «//"dbType" : "dirty",», если поменять его с mysql, то пад переключиться на свою внутреннюю базу данных. Это можно использовать для открытия временного пада на своём хосте, пока MySQL настроен на репликацию главного – а временный пад использовать как средство связи, или писать там адреса альтернативных серверов (раз уж нормальной общей конфы нет).
Для экспорта базы данных, нужно выполнить скрипт «EP_export.bat». Он создаст файл типа «DUMP_$BINLOG.000001$810$.sql.7z», и это – всё содержимое всех падов Пада. Дамп хорошо сжат, и в его названии через «$» отделены параметры мастера, необходимые для старта репликации с него. Слово «DUMP» можно переименовать, но не используйте там специальных символов: только английские буквы, цифры и «_» да «-». Фишка! Чтобы расшарить его (да и не только), переместите файл в папку пада по адресу «\node_modules\ep_etherpad-lite\static\» – тогда он будет доступен из корня сайта (типа http://127.0.0.1:9001/DUMP_$BINLOG.000001$810$.sql.7z )
Для импорта – перетащить нужный «…$…$…$.sql.7z» файл на «EP_import.bat». Это _заменит_ текущее содержимое базы данных «ep» пада на то, что в файле. А вот после полного сброса сервера баз данных, то есть после «MySQL_totalreset.bat» – этой самой базы «ep» ещё не будет, и импорт не удастся: поэтому потребуется сначала запустить «install_db.bat».
Импортирование перехватывает параметры бинарных логов мастера для репликации, и сохраняет их в файл «blog.bat». Кстати! Везде пишут, что для экспорта с репликацией, мастер непременно нужно останавливать, иначе мы не получим значение лога после непосредственного экспорта, ведь в базе к этому времени уже может что-то поменяться. Но мой скрипт делает экспорт как можно быстрее, и сверяет параметры бинарных логов до и после. Если они совпали – значит всё отлично, никаких изменений в паде не было. А если нет – дамп, конечно, создаётся, но он будет непригоден для репликации. Скрипт позволяет зажать Пробел, чтобы продолжать пытаться заново создать правильные дампы до тех пор, пока не получится успеть между коммитами пада в базу. На крайняк можно просто попросить всех с полминуты ничего в пад не писать, либо всё же закрыть сервер пада, если совсем никак не экспортируется.
А вот как нужно настраивать репликацию.
На запасном хосте, нужно развернуть свою копию MySQL сервера, но в файле конфигурации «my.ini» требуется заранее обязательно изменить «server-id=11» на другое число. Пад можно не запускать, достаточно будет «install_db.bat» и импорта правильного дампа с мастера.
Теперь запускаем «replication_use.bat», и консоль спрашивает IP мастера. Его надо аккуратно ввести и нажать Enter. Будет выведен неинтерактивный статус. Окно можно закрыть, а вскоре – выполнить «MySQL_STATUS.bat», чтобы получить больше информации.
В этой большой таблице важнее всего пункты «Slave_IO_State:» – текущее состояние, должно быть что-то типа «Waiting for master to send event». Если там пусто, или какой-нить реконнект – плохо. «Seconds_Behind_Master:» – самое важно, если там «NULL» – репликация не работает. Должно быть число, обычно «0». А «Last_IO_Error:» – сообщение об ошибке, но я-ще не понял, как его очистить. Для перезапуска репликации – можно выполнить «replication_use.bat» и просто нажать Enter, чтобы взять старый IP. Если мастер работает на другом порту – откройте сам скрипт и поменяйте там «echo MASTER_PORT = 3311,»
Остановка репликации – «replication_stop.bat». Кстати, реплицирующий сервер (я надеюсь) блокирует себя для записи, поэтому запущенный к нему пад не должен заработать. Но всё равно, лучше не рисковать, и если на текущем хосте репликация – то в конфиге пада переключить на dirty.
Теперь весь процесс использования репликации:
Первое, назначаем главный хост у кого-нибудь, и запасные хосты. Каждый из них развёртывает MySQL и пад, проверяет, что всё работает. Запасные пады закрываются.
Второе, главный хост снимает дамп с базы (пусть, даже пока там ничего нет) и передаёт его остальным. Те импортируют дамп в базу, и запускают репликацию. Нужно быть уверенным, что она работает. (Для этого можно остановиться и запустить базу для пада, увидеть там новые изменения, всё сбросить и снова импортировать изначальный дамп – репликация всегда «догоняет» мастер от сохранённой точки то реального времени.)
Третье, запасные могут раскрыть пады, настроенные на dirtyDB, просто как альтернатива для связи. Но теперь вся работа проходит на основном хосте.
Четвёртое, мастер упал. Считаем, что связь с хостом потеряна полностью. Нужно решить, чья реплика теперь станет главной. Останавливаем её, и обязательно снимаем новый дамп со своего варианта базы, расшариваем его. Запускается пад, настроенный на mysql, и все переходят в него (правда, цвета и имена больше не будут соответствовать прошлым – это потому что хост другой, и cookie не пересекаются, браузеры войдут как в новый пад).
Пятое, все остальные запасные хосты скачивают дамп с этого, и перебрасывают репликацию на него. Если первый хост оживёт – он может подцепиться как ещё одна реплика.
Если по каким-то причинам, экспорт из базы стал неадекватно большим (хотя он ужимается) – можно просто запустить пад у себя, сделать оттуда экспорт в .etherpad, потом грохнуть базу нафиг, заново пересоздать, импортировать документ в пад, и снять дамп для репликации.
И напоследок: – чтобы сделать рут-пароль к mysql пустым, нужно удалить папки \data и \DB из \MySQLServer5.5\ (это уничтожит базу данных, если что) и вытащить их из файла \bin\restore – это обычный .7z архив. Теперь, удалить мой «pass.bat».
– чтобы использовать другой порт, меняйте в «my.ini» (мастер) и «replication_use.bat» (реплика).
– чтобы сменить пароль для базы пада, ищите в «install_db.bat» и «settings.json» самого пада. Пароль репликации меняется в «install_db.bat» (мастер) и «replication_use.bat» (реплика).
– ещё раз напомню, что путь к папе нудно менять вручную (то есть все файлы нельзя просто так взять и переместить куда-то), а именно в «my.ini» (два раза, с прямыми слешами) и в «path.bat».
– если будете разводить «локальные копии mysql», весящие на разных портах – во-первых, трижды перепроверяйте пути – не то будет так, что батник запускается из одной папки (путь path.bat), сервер на самом деле работает из другой (соединения проходят через порт, а где сам сервер при этом ж не важно), а используемые файлы самой базы – в третьей (my.ini может показывать куда угодно, например на файлы не своей копии mysql). А во-вторых, последний раз когда я проверял (у меня уже не было двух копмов под рукой) – у меня вообще репликация локально не заработала, до мастера не достучалась.
– имя процесса «mysqld.exe» (в \bin\) я намеренно изменил на «tdtpad_mysqld.exe», чтобы если что, не конфликтовать с потенциально имеющимися базами данных, запущенными на хосте. Поэтому, имя также должно быть прописано в «path.bat». Кстати, если на одной машине несколько копий сервера – команда «MySQL_kill.bat» убьёт все, а не только текущую.
Если кто желает сейчас проверить репликацию (пока я не забыл, как всё работает) – давайте. Я не претендую на то, что использовать её в продакшн. Точно сломается что-нибудь.
Если что, в моём архиве по факту уже выполнен «MySQL_totalreset.bat» и «install_db.bat». Файл «for settings.json» ни для чего не нужен, это просто кусок настроек для пада, а папка \tmp\ – туда я скинул все шаблоны для файла конфигурации, чтобы не мешали. Модуль «7za.exe» в \bin\ – добавлен мною, как и файл «restore», содержащий исходную версию внутренней базы самой MySQL. Прочие проги в \bin\, кажется, не нужны; но я не стал их трогать, чтобы не портить целостность самой сборки.
О, я подумал, что неплохо было бы оставить в файле «coment.txt» всё это моё сообщение, чтобы оно всегда находилось под рукой.
– я почти закончил программу! – ага, ага, закончил, конечно… – и там код красиво оформлен!.. – ой, да ладно!! – осталось справку коротенькую написать… – коротенькую!? ВА-ХА-ХА
Ну в общем тут как было… Вставляю я значит, совиный атлас, ну там RipBin, FastWad, PGG и WinHex. Думаю, инструкцию надо написать ещё разок, опять от и до. Да и все программы в единый пакет свалить, хотя ничего нового нет.
Потом, когда вставил – понял, что забыл по факту само изображение-то координатами задать, в соответствии со смещениями из прошлого моего комментария. Ну и я сделал это прямо в памяти, кстати, там где я писал «ширина» – кажется, не столько ширина и высота, сколько координаты противоположного угла рамки (равная ширине и высоте только если позиция в 0,0)
Хотя как видно, приведение было не очень хорошим, нужно попробовать через ещё какую-нибудь программу (с более адаптивной палитрой), а то на затемнении блики разноцветные видны: http://klimaleksus.narod.ru/Files/REPEAT/newatlas_3.jpg
СТОП
…кто-нибудь заметил что-то подозрительное и очень нехорошее?
– картиночки с мирами, подгружающиеся на страницы атласа – используют этот чёрный уголок для динамических текстур, затирая всё его содержимое. То есть не зря там столько места, не зря… А два их небось потому, что очередной нужно подгрузить, не теряя текущий.
Как бы да, первый раз при открытии атлас всегда будет с правильной текстурой, но после закрытия появится неприятный сюрприз.
Итог: не-а, мы не можем менять размер картинки. Придётся втискиваться в оригинальную. А что теперь будет со шрифтом, я даже представлять не хочу.
*UPD*
Ну, координаты взять же надо? Чтобы выжать максимум (как будто бы ещё два пикселя справа можно вытащить, но я чё-т не уверен, ну нафиг!), пришлось пропатчить 179-й по смещению: 6FC0h = 00 18 60 00 83 7F 88 00 – там было «81» вместо «83».
Я просмотрел вашу пробу (она трёхсекундная, всё верно?), и она довольно неплоха. Но увы, слишком короткая, чтобы судить точнее))
Кстати, роль самого Спайро – по сути, эпизодическая роль, относительно всей игры. Основная часть текста принадлежит тем персонажам, которые встречаются на уровнях.
В этой теме можно найти и хорошие инструкции о том, как сделать качественную запись, так и ссылки на некоторые тексты для проб. Но кому хочется копаться в прошлом, верно?
Думаю, мы должны будем ещё раз, с нуля собрать список персонажей и текстов, которые в принципе подлежат озвучке. И мы скоро сделаем это.
А вы, в свою очередь, пообещайте, что не покинете нас, раз уже решили нам помочь и присоединиться к проекту! (Но если что – мы тормоза. Но вы ж тоже никуда не торопитесь?..) but nobody came
На самом деле я хотел ещё раз перевести Тиков. Но задумался о том, нельзя ли как вариант рассмотреть перевод их текста в нестихотворной, но эквиритмичной оригиналу форме, чтобы с абсолютной точностью повторить интонацию? Не знаю, зачем. Если так сделать, то у нас получатся не стихи – но тем не менее, эти фразы обычными уж точно назвать будет нельзя.
Для этого нужно воссоздать исходную слоговую скему, ритмику ударений. Я так делаю транскрипцией, когда перевожу некоторые песни. Но тут не песня, и транскрипция только путает. Однако, можно заменить графическую схему на реальный набор русских слов, которые собираются кусочками с верными ударениями.
Но опять же, где взять слова… Я хотел найти онлайн-сервис, где был бы подбор ударений по маске, но не нашёл. Искал быстрый словарь ударений, чтобы написать свою программу… Но у меня был электронный словарь Ожегова, в котором есть и ударения, и вся база в текстовом формате.
Всё что мне осталось – распарсить это регулярными выражениями, и сверстать интерфейсик:
Использует русские «о» и «х» как маску ударного и безударного слогов; символы можно и поменять. Всё прочие и переносы строк сохраняются, обновление по написанию или щелчку в поле – маски превращаются в рандомные слова (менять отдельно взятые нельзя, но можно использовать вывод повторно в поле…)
Думаю, этот скрипт, вообще говоря, очень даже может пригодиться и при переводе песен, потому что с ним проще наглядно собрать верную ритмику, хотя её и придётся составлять вручную. А ещё это почти что словарь ассоциаций… (если кто внатуре вздумает белые стихи на нём шпарить – смените О/Х символы да хоть на =/+, чтобы русские слова как есть принимались на входе)
Вот Тики, с моей ритмикой. Тут я ориентировался именно на интонацию оригинального произношения, а не на сам текст. Пунктуация – лишь для облегчения при чтении моего суррогата:
352 Rhynocs are running rampant around here, but I can't get anyone out of the Tiki Lodge long enough to do anything about it. хо охо хо ох х, оох охо ох - оохо х х ох - ох оох охо!
126 I'm playing a game of hide and seek with my friends. If I can't find where they've hidden their heads they won't let me join the Tiki Lodge. Help me put them back together and I'll make you an honorary member. х о ох ох ох оох! оох о оохо ох, ох оохо охо х. хо хо х охо, ох о х охооо хо.
277 When you find a head, land on top of it to pick it up. Then fly it over to an idol body to put them back together. оох ох, хо хоо: ооох! охо хо оохо хо ооох охо.
287 When you've picked up a tiki head, fly over to any body and use the square button to drop the tiki head. хо хо охо о, охоо хо хо, охо х хо, охо хоо.
марАл Адрес рЕгент досьЕ. квадрАтный - кИса - шЕлк, скУшать.
318 Are you the dragon looking for all those eggs? Because I saw a shifty looking character with one over there. ох охо хо ооох? ооох - охо, хо хоо ох, оох.
1054 Hey, there goes another one. He was really fast... maybe if I activate the supercharge you'll be able to catch him. х! ооохоо. хо хо х. хо оохоо охоо, х оохо охо!
стек прямОй обшАрить прострогАть, свинопАс рассекАть! склеп! влиЯть: обезлИчить.
1013 I'm late for a dinner party at the Tiki Lodge, and the portal to my home just stopped working. Maybe the portal will reactivate after a few more dragons hatch. ох оохо хо - оохо о, оохо оох - ох хо. хо, охоо охоо, ооохо хоо.
Ну вот я поозвучивал – CloudSpires и SunnyVilla. Чудики-импы: (мне абсолютно не подходит этот персонаж…) http://klimaleksus.narod.ru/Files....mps.mp3 – структура: оригинал, первый вариант, второй вариант. Варианты отличаются логическим ударениям на слова. Может, на каких-то репликах я случайно выбрал не те варианты, но в общем, это верно.
1097 The rhynocs have shut down our cloud generator and I'll never see a rainbow again. Носороги заглушили наш генератор облаков, и теперь я никогда не увижу радугу.
469 You'd think the Sorceress would want more rain, after what the sun has done to her skin. You would think Казалось бы, Колдунье захочется ливня, после того, что солнце сделало с её кожей.
414 If my wings were big and strong like yours, I could easily glide across here. Были б мои крылышки большими и сильными, как твои - я бы запросто тут пролетел.
452 Oh, you activated the bellows? Maybe I can get the cloud generator working again... О, ты запустил меха? Может, теперь я смогу включить наш генератор облаков...
479 The rhynocs must have been using this thing to clog up the cloud generator. Похоже, этой штукой носороги и заткнули наш генератор.
1023 Our sun has gone out. We can make a new one with our lava fusion cauldron and three sun seeds, but they keep burning out before we can get them in the pot. Наше солнце угасло. Мы можем создать новое, сплавив три солнечных зернышка в котле лавосинтеза, но они сгорают прежде, чем мы их туда донесём.
1096 Step on the switch to get a fresh sun seed and keep flaming it until you get it into the pot. Шагни на кнопку, чтобы сдвинуть солнышко, и подогревай его, пока оно не окажется в котле.
276 Now that's what I call a sun! Here, you can have this last sun seed as a souvenir. I think it might be a dud, though. Вот это я называю солнцем! Да, можешь забрать оставшееся зернышко на память. Но, по-моему, оно никуда не годно.
350 If you can't keep up with the sun seed, remember you can always hold down the > button to charge. Если ты не поспеваешь за солнышком - помни, что с кнопкой квадрат можно бежать быстрее.
319 We usually wake up our rain cloud at the crack of dawn, but these mischievous spirits are stopping our bells from ringing. Обычно мы будим дождевое облако на рассвете, но эти проказливые духи мешают нашим колоколам звонить.
525 Do you want this doodad? It fell out of the belfry. Тебе нужна эта безделушка? Она выпала из колокольни.
99 Well, well, if it isn't my favorite dragon! The Sorceress has put me in charge of guarding these bellows. However, I suppose I might look the other way if I was distracted by counting gems. Так-так, неужели это мой любимый дракон! Колдунья поручила мне не сводить глаз с этих мехов. Но, знаешь... ничто не отвлекает сильнее пересчёта камней.
168 Oooooh yes... precious, precious gems... Well then, Spyro, you may now use the bellows any time you wish. Best of luck on your little egg hunt. О-о-о да... мои прелестные, прелес-с-стные самоцве-е-еты... А, ну да, конечно, Спайро, можешь залезать на меха, когда пожелаешь. Удачи в охоте за яичками.
1022 What? NO? What else are you going to do with all those gems? Buy flying lessons? (Heh heh) that was a good one... Что? НЕТ? Но что ты будешь делать с этими камнями? Заплатишь за уроки полётов? Хе-хе, неплохо сказано… / Заплатишь за обучение полёту? Хе-хе, это ж бесценно...
81 Sorry, Spyro, it is my sworn duty to make certain no one crosses these bellows. And you know perfectly well that nothing could ever sway me from obeying my sworn duty... that is, ahem, until you have a few more gems. Прости, Спайро, но это мой долг - неусыпно стоять на страже мехов. И ты отлично знаешь: ничто и никогда не заставит меня от него отступиться! Ну разве что... если бы у тебя было чуть-чуть побольше сверкающих камешков...
367 Heh heh... I haven't made such easy money since the Sorceress bought that mayonaisse for sunscreen. Хе-хе... Я не получал деньги так легко с тех пор, как продал Колдунье майонез от загара.
Зоя из второго уровня, плавно переходящая в первый и шейлу-марко-рапунцель: http://klimaleksus.narod.ru/Files....zoe.mp3 – разные варианты в 251, 1099 (моя актёрская правка: «для твоих рогов» звучит так, будто я «врагов» выговорить не могу…); а в «I've moved out» замечали какая интересная интонация?
278 Remember, to get your longest glide press the < button at the very top of your jump, and use the } button to hover at the end of your jump. Не забудь, чтобы лететь дальше, нажимай крест в самом пике прыжка, а в конце полёта нажмитреугольник, чтобы подняться повыше.
251 The metal armor those enemies are wearing protects them from your dragon flame. If you hold down the > button, you can defeat them with your charge attack. Этих врагов от твоего пламени защищает стальная броня. Ты с ними справишься, если протаранишь их с разбега, нажав круг. / Но ты сразишь их, если протаранишь с разбега, нажав квадрат.
1099 This rhynoc is too big to charge. You'll have to flame him using the { button. Здравствуй, Спайро! Этот носорог великоват для твоих рогов. / Твои рога не справятся с этим носорогом. Подожги его, нажав кнопку круг.
1132-368 Hi Spyro! Each time a fairy zaps you, like this... That means your progress is saved. If you get into trouble you'll return to the last place you got zapped. И снова привет! Когда я делаю вот так… …это означает, что игра сохранена. Если с тобой что-то случится, ты вернёшься на место сохранения.
450 What! Marco sent you here? I've got a restraining order against him. Что! Тебя прислал Флино? Вообще-то, он здесь –персона нон грата.
540 If you see Marco please tell him I've moved out. Если увидишь Флино – передай ему, что я переехала.
369 Hey Spyro, there are rhynocs everywhere. Maybe I can find some peace and quiet at the top of the tower... Эй, Спайро, тут повсюду носороги. Может, на вершине башни я смогу побыть в тишине и покое...
312 Alas, I have lost my love, guarded by evil rhynocs at the top of yonder tower. Can you rescue her for me? Увы, я потерял свою любимую, её охраняют злые носороги на вершине вон той башни. Ты можешь её для меня вызволить?
Львята… у них я заметил такой акцент на букву «р». Оно не по-английски произносится. Я попробовал вторым вариантом – сделать «р» явной, будто я озвучиваю попугаев.. Там, где ни одной эр в тексте нет – поменял текст: http://klimaleksus.narod.ru/Files....leo.mp3 – а именно в 1153, 497 и 477; в 296 потерял не р-р-рэшную озвучку, а в 381 – местоимение «я».
1053 Oh my! Oh my! Can you help us? Hordes of ferocious rhynocs have overrun our town and kidnapped the mayor. Караул! Беда! Может, ты нас спасёшь? Полчища озверевших носорогов набежали на наш город и захватили мэра!
518 Are you a dragon? I never believed you really existed. Ты что, дракон? Вот уж не верил, что вы существуете.
524 Would you like a chicken sandwich? They're very good. Хочешь булочку с курятиной? Чудесная вкуснятина!
468 Those pesky rhynocs are back again, but I'm sure you'll soon sort them out. Эти вредные носороги снова вернулись, но я уверен, что ты быстренько с ними управишься.
1153 Let me catch my breath and I'll kick that other guy's butt. Сейчас отдышусь, и сам наваляю тому негодяю! Сейчас бы отдышался и сам потрепал того негодяя!
296 We showed those two bullies. If they hadn't outnumbered me two to one, I'd have finished them off ages ago. Мы проучили этих хулиганов. Не будь их двое, я бы и сам давным-давно справился.
1170 Have you seen any giant chickens around here? А тебе тут не попадались огромные курочки?
381 Thank you for rescuing my town. As mayor I award you with one of our famous giant chicken eggs. Благодарю за спасение моего города. Как мэр, я награждаю тебя одним из знаменитейших огромных куриных яичек.
477 I'm sorry, that was the ugliest chicken I've ever seen. Сожалею / Прости, это был самый гадкий цыплёнок на свете.
531 Whoo I'm dizzy. О-ох, мне дурно.
497 Thanks for the help, but I think I would have worn him down in a minute. Спасибо за помощь. Но ещё минута - и я бы его вынес. / - и я бы его просто вынес.
1094 Have you seen any of our giant chickens? The rhynocs have been trying to eat them all. Ты огромных курочек нигде не видел? Носороги хотели всех их слопать.
495 Look, a chicken turned up. I hope it's not the only one left. Гляди, одна курочка нашлась. Надеюсь, уцелела не только она.
А вот и Хантер: http://klimaleksus.narod.ru/Files....unt.mp3 – я уже так запарился к этому времени, что просто записывал в один заход, по одному дублю без второго варианта. Может поэтому бывало, что временами вылетал из роли. А ещё на первой фразе микрофон трещал…
236 Hi Spyro. I found this gladiator training arena and it makes a pretty cool skate park! Care for a test of your boarding skills? Здарова, Спайро. Я отыскал арену гладиаторов, а из неё вышел классный скейтпарк! Поупражняешься на скейте?
1172 Are you ready for a challenge now? &Start boarding challenge now? Ну что, надумал наконец-то?
262 I bet you can't catch all fifteen of the lizards running around here... Just come back if you want some boarding tips from the master. Спорим, тебе не поймать 15 ящериц, что бегают где-то здесь... Если нужен совет спеца по скейтам, обращайся.
349 Yeah, maybe you'd better practice a bit first... Just come back here when you're up for a challenge. Да, может тогда сперва потренируешься? А как созреешь для чего посерьёзней - приходи.
298 Having trouble? If you use the < button to jump off the ramps you'll get extra height and distance. Проблемы? Держи кнопку крест при прыжке с трамплина – так пролетишь гораздо выше и дальше
1031 Caught all the lizards yet? If you're having trouble catching them, don't be afraid to use your flame breath while on the skateboard. Всё гоняешься за ящерками? Если вдруг не ловятся – не бойся их поджаривать прямо со скейта.
361 Hey that was great! And while you were boarding, I found this in a lizard burrow. Эй, вот это крутяк! И пока ты там катался, я кое-чего откопал в норке ящерицы.
214 Now that you've mastered the basics, let's see you do some stunts! Try using the < or } button to jump off ramps and turn in the air... Теперь, когда ты знаешь азы, давай освоим несколько трюков! Попробуй нажать < или } чтобы прыгнуть с трамплина и крутануться в воздухе.
440 This is the most fun I've had since we chased King Flippy on the manta ray. Круче на скейте кататься, чем на скате за Флиппи гонятся!
161 Alright, if you can catch all the lizards without wiping out and before time runs out, I might be able to scrounge up another egg. It's not gonna be easy, though... Хорошо, если ты за три минуты поймаешь всех ящерок и не рухнешь со скейта, может быть, я и раздобуду ещё одно яйцо.Уж и нелегко тебе придется... // за три минуты ты
1124 If you want to try to catch those lizards, I'll start the clock now. Если собрался ловить ящериц – я запускаю таймер.
534 Go get'em, Spyro! Поймай их, Спайро!
535 Well whenever you're ready, come and talk to me. Ну чё, как будешь готов – сообщи.
1125 Awww, too bad... maybe you'll do better this time. Ой, отстой... Может, в этот раз получится?
371 Whoa, that was sweet! And look, there was another egg in the lizard burrow. Это отпад! Гляди-ка, а в норке у ящерицы было два яйца!
123 You can go for the course record now, if you want. Whenever you hop on a skateboard, a timer will start. Score as many points as you can until the timer expires or you wipe out. Good luck! Попробуй поставить новый рекорд, если хочешь. Когда встанешь на скейт, включится таймер. Набери как можно больше очков, прежде чем закончится время. Удачи!
– в 349 поменял «лады» на «да», потому что там другая интонация оригинала; а в 161 – слова сами местами поменялись… but nobody came
Программа для быстрого запуска сохранёнок эмулятора Epsxe.
Установка: 1) Поместите файлы «SavestateRunner2V0.exe» и «SavestateRunner.bin» в папку с эмулятором. 2) Запустите «SavestateRunner2V0.exe». Возможно, откроется окно эмулятора (если настойки по умолчанию сработали), его можно закрыть. 3) Появится файл «SavestateRunner2V0.ini», откройте его Блокнотом. 4) Если нужно, измените значение «EPSXE_EXE=ePSXe.exe» на имя исполняемого файла вашей копии эмулятора – например, на «EPSXE_EXE=ePSXe200.exe». 5) Эмулятор должен быть версии 1.7.0. Если это не так, то вам нужно как-то выяснить адрес в его памяти, по которому можно достать идентификатор запущенной игры, и внести его в строку «GAME_ID_PTR=12650304» – например для Epsxe 2.0.0 этот адрес равен «GAME_ID_PTR=23256000». 6) Если вас интересует только какая-то конкретная игра – впишите путь к её образу в строку «DEFAULT_IMAGE=SavestateRunner.bin», например «DEFAULT_IMAGE=D:\DATA\Spyro-Year-Of-The-Dragon gh.iso»
Использование: 1) Снимите дубликат с любой своей сохранёнки (они копятся в подпапке «sstates\»), и смените её расширение на «.SavestateRunner». Например, файл «SCUS_944.67.002» можно переименовать в «SCUS_944.67.000.SavestateRunner». Файл сохранёнки получит иконку. 2) Его можно запустить! Тогда, откроется настроенный эмулятор, в который будет загружена эта сохранёнка, как открытая на образе по умолчанию (изначально «пустой»). Если эта сохранёнка от другой игры – скорее всего, рано или поздно всё сломается. 3) Чтобы запустить сохранёнку под образом конкретной игры – перетащите ваш образ, например .iso, на неё саму – на файл .SavestateRunner (он будет вести себя как «программа», позволяя перетаскивать на себя), и эмулятор загрузит данную сохранёнку с этой игрой. Если сохранёнка действительно от этой игры, то всё должно работать идеально. 4) Также, можно перетаскивать сохранёнки на «SavestateRunner2V0.exe». Либо изменить в настройках опцию «DEFAULT_IMAGE», чтобы задать образ по умолчанию для всех сохранёнок, открытых двойным щелчком, а не перетаскиванием образа на них. Технически, для самой программы: первым аргументом передаётся сохранёнка, а вторым – образ, если есть.
Ограничения: 1) Когда сохранёнка будет запущена – чтобы вручную производить сохранение и загрузку, а также совершать другие действия горячими клавишами Epsxe – вам необходимо один раз нажать F3. Например, вы можете делать свои сохранения после загрузки изначальной – и для этого вы попытаетесь нажимать F2, но окошко с картинкой не станет появляться, пока кнопка F3 не будет нажата хотя бы однажды (первый раз «загрузка savastate» не выполнится). 2) Сворачивание эмулятора через Escape, или любая другая попытка поставить игру на паузу – закроет эмулятор. Чтобы не потерять свой прогресс, сохранитесь в какой-нибудь слот вручную через F1, чтобы потом загрузиться через F3. Но не сохраняйтесь в первый слот, потому что он будет перезаписан при следующем же открытии исходной сохранёнки (которая, кстати, не будет перезаписана ни при каких обстоятельствах), а примените F2 и выберите другой. Если вы желаете продолжить работать с сохранёнкой в эмуляторе так, чтобы иметь возможность сворачиваться в меню, то просто запустите эмулятор обычным способом, выберите открытие того образа, через который была загружена данная сохранёнка (для образа по умолчанию, выберите «SavestateRunner.bin») и нажмите F3 сразу после инициализации эмулятора. but nobody came
Ибо всякий, кто дочитывал ту простынищу до конца, вылетал с ошибкой «System Out of Memory»
Да у меня такое от любой страницы этой темы… Короче, я отсюда и вверх.
ЦитатаТомас
отдельный пост со всей нашей концепцией?
Нужен, да. И глоссарий, чтобы не вспоминать, а было ли в названии какого-либо уровня такой-то игры данное слово, или пока свободно.
ЦитатаТомас
Вроде количества врагов для усилителя в Бризовой Гавани.
Тогда это надо тащить ещё с постов Йамса со времён Вихря…
ЦитатаТомас
Пересобрала посты по именам и обновила шапку. Внесла правки.
… КА-А-АК!? Что у тебя там за формат такой внутренний, что и правки вносятся легко, и в BB-коды отлично выгружается? А цепочки цитат-то как собирать…
ЦитатаТомас
Справедливости ради, в тексте уровня такого сочетания нет.
Я просто озвучил логическое продолжение на слово «бесплодный» и утверждение, что «скелос» тогда не будет звучать как имя существа. Отнюдь. Старичок такой костлявый получается – ну, он вроде и бойкий такой, но увы.
ЦитатаТомас
То есть дубина он и есть. И в самом слове «Гронк» есть что-то от удара дубинкой. Грох?
О, только сейчас понял, что «Грох» – это от «грохнуться». Грох… где был грох? В каком-то полнометражном мультике. Возможно, он был маленький. Возможно, ребёнок или питомец. Я думал, «грох» – это от «горошина», почему-то. Или, мол, «грох ему цена»…
Так ещё раз, я не понял: имена переводим или нет!? Или и так и так?
Потому что тут среди всех постов – постоянно по два варианта. Между ними идёт выбор, или нет? И если, скажем, три персонажа на одну тему – то нельзя же двух транслитерировать, а последнего перевести.
ЦитатаТомас
Итого, Гонки или Трасса?
…а почему не «Гонка»?
Кстати, «time attack» пираты, по-моему, переводили как «гонка со временем» (может, не в этой игре).
ЦитатаТомас
Foreman – Прораб, Мастер, Бригадир?
ЦитатаТомас
В крайнем случае можно устроить им распределение по специальности: cлесарь, сварщик, плотник, монтёр…
– вот плотник вроде подходит. Ещё я думал об инженере. Но мастера нормально. У нас же мастеров больше нигде, включая все игры и названия миров – нет?
ЦитатаТомас
Что вообще за дела с этой длиной? При всей той магии, что уж есть, просто-таки стыдно не покорить её.
Вторую игру не ломал. Но рюкзак должен по идее сработать. Надо его уже закодить наконец.
ЦитатаТомас
Fracture Hills – какие Холмы?
Может, трещащие…
ЦитатаТомас
Насчёт Глиммера, Колоссуса и Хуррикоса
Как-то они через один в списке следую – одно слово, два слова.
ЦитатаТомас
Они ж при каких-то условиях могут попеременно всплывать или нет?
О, это проверять надо.
Кстати, я во время игры никогда на её телепорт не соглашался: я же хочу знать, как я туда попал…
ЦитатаТомас
Это наверное был самый вопиющий перегиб во всём тексте.
В смысле, что последний вариант – находка? Ну да, не могу не согласиться.
ЦитатаТомас
Если верить искушённым, некоторые фразы в игре, хотя и не отмечены «нулём», можно услышать только с читами:
О, это же тот сайт, что скриншоты из SWV использует!
ЦитатаТомас
И «Жорик» произнести легче, чем «Джорджик»
, если именно «Джорджик», а не «Joрjик».
ЦитатаТомас
Когда всё в одном посте, я могу с первого же взгляда мысленно на всё ответить. И уже буквально через месяц я вспомню, что надо бы это ещё и написать. А если нужно ещё что-то дополнительно открыть... этот процесс немного усложняется.
+
ЦитатаSerlutin
Ну так видеоинструкция же не вышла. Вот Арчик и не сможет разобраться.
Бли-и-ин… Точно же. На самом деле, мне очень-очень стыдно…
ЦитатаSerlutin
гораздо проще записать и кинуть ссылку, чем 1. Скачать 2. Установить 3. Записать и сохранить в файл 4. Выложить этот файл куда-нибудь 5. Отослать ссылку.
Ну нет. Это как «перепечатать с бумаги» v.s «установить дрова на сканер + найти программу по распознаванию текста + отсканировать + исправить документ». В перспективе – второе куда предпочтительнее.
Плюс тут же для озвучки – и качество / настройки оборудования / формат файла.
ЦитатаТомас
а Зою добавила к остальным боссам.
Мне как-то приснилось, что в Зою, которая появляется рядом с воздушным шаром и сообщает о взломанной игре – в неё вселилась Колдунья: она появилась с синеватым оттенком и весьма криповымы чёрными пустыми глазами, и применяла против Спайро стандартные атаки колдуньи. Потом сумела себя обуздать, сказала, что теперь дракону придётся продолжать без неё, и самоуничтожилась, успев как-то наложить проклятье, от которого все самонаводящиеся снаряды на протяжении игры наоборот отклонялись всё дальше от цели.
ЦитатаТомас
я знаю одного Джавахарлала... но все называют его Жорой
Да у нас почти всё через Жору сделано.
ЦитатаТомас
В то же время, лазание по специальным стенам – тоже разновидность скалолазания. Так что на мой взгляд, это не так критично.
А вот эти выделения зелёным – в оригинале они являются неизменными терминами. А у нас будет «летать»/«пролетишь», «лазить»/«карабкаться» – и так далее – и нормально!?
ЦитатаТомас
Игрок и камера – это ж две стороны. Пассивная камера – активный ты: больше контроля. Разве нет?
Я всегда на активной, кроме очень редких случаев, когда требуется какой-то хитрый манёвр. С пассивной же приходится постоянно вручную управлять ей – хотя я и умею это делать.
Видимо, это как ручная или коробка-автомат в играх про гонки. Ну кто в своём уме выбирал ручную!? ))
ЦитатаТомас
*Возвращение блудного Томаса*
Уф. Ну вот, насколько смог в историю погрузиться – настолько смог. По обсуждениям… на там уже как бы не актуально, последние варианты-то недалеко, а все споры устарели. По репликам… ну она вроде достаточно хороши. Может максимум где-то запятая спорная, но куда большей пользой было бы проверить по озвучкам, чего я не делал. А по именам или названиям мне даже придумать вроде нечего, я в саму игру значительно меньше по факту играл, чем в Spyro3 (я ж только его постоянно ломаю), и поэтому что-то революционно новое и подходяще мне не создать.
Насчёт каждого названия можно и подискутировать, но многие из них – КАК ЕСТЬ – меня устраивают. А остальные – они могут зависеть от чего-то ещё, или их хочется потом увидеть все вместе одним списком… Так что я сейчас достаточно бесполезен. but nobody came
388 You can Hover to get more distance when gliding. Just press the } button at the end of your glide. &[Press } button at the end of your glide to get more distance. Ты можешь взмахнуть крыльями, чтобы пролететь чуть дальше. Просто нажми } в конце. &[Перед самым приземлением жми } и окажешься подальше.
314 If you want a quick summary of your progress in a world, you can press the @4SELECT@0 button to open the Atlas page for the world you are in. &[Press @0SELECT@4 button to view Atlas. Если хочешь узнать о своих успехах, нажми @4SELECT@0,тогда откроется Атлас на странице мира, в котором ты находишься&[Открывай Атлас кнопкой @0SELECT@4.
90 While I was gone, my friends borrowed the rhynocs' submarine... then they took it for a joy ride... and then they smashed it into a big pile of rocks. Oddly enough, the rhynocs failed to see the humor in the story and stuffed my friends in the jail behind you. Пока меня не было, мои друзья стащили подлодку носорогов... ну, погоняли на ней... а потом врезались в здоровенный риф! Как ни странно, носороги не поняли юмора и запихнули бедолаг в клетку позади тебя.
380 The rhynocs have boarded up a lot of our doors, but I bet you're strong enough to smash them down. &[Use charge to smash boards. Носороги заколотили добрую половину дверей, но уж ты-то без труда их разнесёшь. [&[Выбей доски с разбега.
297 My plan worked! That dumb octopus dropped the jail key while he was shaking me! Now I can free my friends... Сработало! Этот тупой осьминожка выронил ключ от клетки, пока пытался меня защекотать. Теперь уж я выпущу друзей...
1112 Oh, I forgot to tell you... one of the rhynocs had this egg in his lunch box... О, вылетело из головы. Мне попалось это яйцо в тарелке у одного носорога.
366 I can't wait until the rhynocs build a new submarine! Next time it's my turn to drive! Жду не дождусь, когда же носороги построят новую подлодку! Чур, я буду за рулём!
413 Driving that submarine was a blast! Next time we're going to borrow the rhynocs' speed boat! Гонять на подлодке - просто бомба! В следующий раз свистнем у них скоростной катер!
1055 We never would have crashed that submarine if Sal hadn't tried that hand-brake u-turn during an inverted barrel roll. Мы бы и не разбили подлодку, если бы Сэл не решил устроить крутой разворот на ручном тормозе прямо посреди полубочки
121 Bluto the rhynoc has challenged us to a naval battle. Our speed boat versus his nuclear shark submarine. If we win, we get the dragon egg he's guarding. If we lose, we have to spend a month in K.P. Носорог Блуто вызвал нас на морское сражение. Наша скоростная лодка против его ядерной подлодки-акулы. Если мы выиграем, он отдаст драконье яйцо, которое охраняет. Если проиграем – то месяц будем в К.Р.
1171 Whaddya say, do you want to take on Bluto? &Fight the nuclear shark sub? &Yeehah! &You gotta be kidding. Ну чё как, хочешь всыпать Блуто? &Сразишься с ядерной подлодкой? &Дааа! &Шутишь, что ли?
1130 OK, good luck! Just remember, stay away from the sharp end! &[Press the < button to speed up. &[Press the { Button to fire a missile. &[Pick up crates to get more missiles. Да, покажи ему, где раки зимуют! И держись подальше от акульей морды. &[Жми < для ускорения. &[Стреляй кнопкой {. &[ Подбирай ящики с ракетами.
339 I don't blame you. I already owe seven years of kitchen duty, and I'm not about to risk getting another month! Ладно, ты не виноват. Просто я в Кухонном Рабстве на семь лет вперёд, и получать ещё месяц мне ни к чему!
246 Wow! That's the first time Bluto has ever lost! You've got a lot of talent for someone so purple... I hope this egg was worth all the trouble. Ого! Впервые в жизни Блуто проиграл! А ты весьма способный для… настолько пурпурного. Надеюсь, яйцо хоть стоило того.
1004 We had a dragon egg for you, but we used it to test our ultra-high-speed-super-fluidity tunnel. The good news is that it made it to the end of the tunnel without a scratch! The bad news is that there's no way to get it back out now. У нас было драконье яйцо для тебя, но мы протестировали им наш супер-высокоскоростной-ультратекучий тоннель. Хорошая новость - яйцо добралось до конца туннеля без единой царапинки! Плохая - теперь мы не можем его оттуда достать.
288 The tunnel is chock full of rhynocs and floating mines. The only way to retrieve that egg is to defeat every single rhynoc in the tunnel. Туннель битком набит носорогами и плавучими минами. Так что яйцо не достать, пока не выбьешь оттуда каждого носорожку.
275 This egg has surprisingly good fluid dynamic characteristics. From now on, all of our submarines will be egg-shaped. У этого яйца поразительно хорошая обтекаемость. Отныне, все наши подлодки будут в форме яиц.
1111 You'll have to defeat every single rhynoc in the tunnel before you can recapture the egg. Нужно избавиться от всех носорогов в туннеле, только тогда ты вытащишь яйцо.
133 Hi, Sheila! The rhynocs have built a fortress on our beach and we're going to blow it to smithereens! We just need you to take out all the turrets for us. We're lighting the bomb now, just make sure to stomp all those turrets before the fuse runs out, OK? Привет, Шейла! Носороги построили крепость на нашем пляже, и мы собираемся разнести её на мелкие кусочки! Только нам нужно, чтобы ты разобралась с пушками. Мы поджигаем бомбы, а ты поломай все пушки, прежде чем сгорит фитиль, ладно?
289 Wow! I can't believe I survived that blast! It's a good thing I kept this egg nice and safe in my pocket. Ого! Поверить не могу, я пережил взрыв! Как хорошо, что это яйцо лежит целёхонько у меня в кармане.
550 Ready to try stomping the turrets again? &Try again? &Yes &No Попробуешь снова разрушить башни с пушками? &Ещё попытку? &Да &Нет
516 Yippee! I'll light the fuse on the next bomb! &[Stomp all turrets before bomb explodes. И-и-ха! Я подожгу фитиль новой бомбы! &[Разбей все пушки, пока бомба не взорвалась.
480 No problem. We'll be playing hot potato with this bomb until you come back. Ну ничего, мы поиграем с бомбой в "горячую картошку", пока ты не вернёшься.
399 Owww... That really smarts... No problem though, we've got more bombs!!! А-а-ай... Какая бо-о-оль! Ну да ладно, у нас ещё полно бомб!!!
1179 Our beach is your beach. Наш пляж - твой пляж.
567 Stay and get a tan, if you like. Позагорай, если хочешь.
221 Oh, hi, Spyro! Some of my seal friends are trying to take down a rhynoc fortress! I'm about to go and lend a foot... I love the smell of singed rhynoc in the morning! Приветище, Спайро! А мои друзья крепость носорогов сносят! Пойду-ка приложу к этому ногу... Люблю запах жареных носорогов по утрам!
– на этот раз по одному варианту озвучки. И я как-то сразу стал потоком записывать, и как-то микрофон плохо встал, слышны пыки на «п» и «б». А ещё мне кажется, если я помещу жевательную резинку себе в правильное место, то буду меньше шепелявить… Надо потом попробовать.
1030 I want to repay you for saving me from that octopus. We can help you use this hot air balloon, if you just bring back someone from each of the other worlds. Ты спас меня от осьминога, и в ответ я бы хотел помочь тебе с воздушным шаром. Только приведи кого-нибудь из остальных миров.
561 Let's head on over to the balloon! Погнали к шару!
1161 The balloon's all ready, sir! Just jump on! Шар полностью готов, сэр! Просто запрыгивайте!
167 Here I was, about to go for a nice swim at Shell Beach, and my portal just disappeared right in front of me. If you go find some more of those dragon eggs, I bet this portal would turn on again. &[^^ eggs needed to open portal. Я было собирался искупаться на Пляже Ракушек, как мой портал внезапно исчез прямо передо мной! Может, если ты найдешь больше драконьих яиц, он снова появится. &[^^ яиц откроют портал.
453 Yay, my portal is working! I'll see you at the beach! Уря, мой портал работает! Увидимся на пляже!
237 I think something is draining the magic out of the world. They say things have been going downhill ever since the dragons left here a thousand years ago. По ходу, что-то выкачивает магию из этого мира. Говорят, все пошло наперекосяк с тех пор, как отсюда ушли драконы, аж тысячу лет назад.
313 I don't know how this balloon works, but I think we can get it working for you if you bring back someone from each of the other worlds. Понятия не имею, как устроен этот шар. Но похоже, что на нём можно взлететь, если ты приведёшь сюда кого-нибудь из других миров.
1044 I guess you just hop in the balloon, now... Don't ask me how it works, I just showed up for the punch and cookies, a ha ha ha. Наверное, надо забраться в корзину... Не знаю, как эта штука летает, я просто заглянул на чай с печеньками, ха-ха-ха.
1173 Let's head on over to the balloon! Ну же, вперёд к шару!
264 This is a balloon that will take you to a new land, but we can't use it until you bring back one person from each of the five worlds. Этот шар доставил бы тебя в другие края, но его не получится опустить, пока ты не приведёшь по одному обитателю из каждого мира.
530 Hop in the balloon whenever you want, Spyro! Запрыгивай в корзину когда пожелаешь, Спайро!
552 Let's head on over to the balloon! Пошли скорее к шару!
80 I see an egg at the bottom of this lake. I would go get it, but I don't want to get my fur all wet. Maybe you could get it. You can dive underwater by pressing the > button when you're on the surface, and charge underwater by holding down the > button. &[Press > button to dive underwater &[Press < button to swim &[Hold down > button to charge underwater. Я вижу яйцо на дне озера. Я б его вытащил, но мне не хочется до шерстинки промокнуть. А вот тебе это не грозит. Прыгай в воду и ныряй, нажав >. Держи > - и ты ускоришься. &[Нырни кнопкой > &[Удерживай <, чтобы плыть &[Для ускорения держи >.
263 Remember, press the > button to dive underwater. Then, when you are under the surface, hold down the > button to charge. &[Press > button to dive underwater &[Press < button to swim &[Hold down > button to charge underwater Запомни, чтобы нырнуть, нажми кнопку >. А когда ты уже под водой, держи >, если хочешь ускориться. &[Нажми >, чтобы нырнуть &[Нажимай кнопку <, чтобы плыть &[Держи > - и ты ускоришься.
94 Yo, Spyro! I just found one of those portal thingamajigs that leads to a different world, but you'll have to glide to get across to it. Press the < button to jump, then press the < button again while you're in the air to glide! Just follow me... &[Press < button to jump. &[Press < button in mid-air to glide. Йоу, Спайро! Я тут нашёл одну из этих штуковин - порталов, которые ведут в другие миры, но до него ещё нужно долететь. Нажми < для прыжка, а когда будешь в воздухе, жми его снова - и ты полетишь! Двигай за мной. &[Прыгни кнопкой < . &[ В воздухе нажми <, чтобы лететь.
478 To get the best glide, press the < button at the very top of your jump. Чтобы пролететь дальше, тыкай на < в самом верху прыжка.
1014 I saw something shiny in that cave over there...let's go check it out! You can get there by hovering. To hover, just press the } button at the end of your glide! &[Press the } button at the end of your glide to hover. &[Hovering will give you extra height and distance. Я вижу что-то блестящее вон в той пещере... давай узнаем, чё это! Но тебе бы вспорхнуть чуток, чтобы добраться дотуда. Так что жми кнопку } в конце полёта! &[Завершая полёт, нажимай кнопку }, чтобы взмахнуть крыльями. &[Ты пролетишь выше и дальше.
166 To get the best glide distance, press the < button while walking forward, then press it again at the top of your jump. Finally, press the } button just before you get to the landing to hover. &[Pressing the } button gives you extra glide distance! Чтобы пролететь как можно дальше, шагай вперёд и зажми кнопку <, а когда высоко подпрыгнешь, нажми её ещё раз. Затем не забудь про }, когда уже идёшь на посадку. &[ } в конце увеличит полёт!
498 Oh, I almost forgot, I found this egg! Ой, чуть не забыл, я же нашел это яйцо!
183 There's definitely something shiny at the bottom of this hole. I was about to jump down there, but I think I hear running water and I hate to get wet. It's a cat thing. На дне этой дыры точно чё-то блестит. Я уж было собрался туда прыгнуть, как услышал, что внизу журчит вода. А я ненавижу намокать. Кошачьи заморочки.
71 I'm getting paid a fortune to keep Sheila the Kangaroo locked up... heh heh... the pesky animal must have been causing a lot of trouble for that poor Sorceress... I suppose I could accidentally let the kangaroo escape... if you were to pay me, say...a small fee. &Pay ^^^ gems to free Sheila? &Sure. &No thanks. Я получаю огромные деньжищи за то, что держу Кенгуру Шейлу под замком... хе-хе... это надоедливое животное сильно досаждает бедняжке Колдунье. Но замочек, совершенно случайно, мог бы и сломаться… скажем... за небольшую плату. &Выпустишь Шейлу за ^^^ камней? &Конечно. &Нет уж, спасибо.
182 Ahhh, Spyro, I love your sweet naivete... Your kind-hearted nature might be your downfall someday, but for the time being it's making me rich! Ах, Спайро, как же мне нравится твое милое простодушие... Твое доброе сердечко может подвести тебя когда-нибудь, но пока что оно делает меня богатым!
220 Well, don't worry, Spyro. Sheila won't stay in jail forever... The Sorceress is thinking about having her executed next Thursday. Ну, не расстраивайся, Спайро. Шейла не останется в клетке навечно... Колдунья подумывает избавиться от неё в следующий четверг. После дождичка.
181 The Sorceress has asked me to guard Sheila the Kangaroo. I suppose, if you had a bit more money, I'd be willing to let her escape. Then you could keep her for a pet or something. &[^^^ gems needed to free Sheila. Я охраняю кенгуру Шейлу по просьбе Колдуньи. Думаю, мне бы захотелось посодействовать её побегу, будь у тебя побольше денег. Она может стать твоим питомцем… Или ещё кем-нибудь... &[Свобода Шейлы стоит ^^^ камней.
43 Spyro! My my, how funny to see you here! Why, I haven't seen you since we defeated Ripto in Avalar... heh heh... Well, my business went into a slump after you left, so I came here and struck up a nice deal with the local Sorceress. Lovely woman, she is. Seems to be very fond of dragons, too... Спайро! Мой дорогой, как здорово увидеть тебя здесь! Мы не виделись с тех пор, как разгромили Рипто в Аваларе... хе-хе... Конечно, с твоим уходом мой бизнес прогорел, и вот я пришел сюда и заключил дивную сделочку с местной Колдуньей. Какая женщина... Кажется, она тоже без ума от драконов...
365 Ну, похоже, теперь мы вдвоём. Я буду в тылу, а ты – разбей злодеев.
451 Глянь, тут яйцо. В Ложе Тики в ночь вчера раздавали их – возьми.
126 Я вёл друзьям игру «мороз-горячо». Не найти мне, где же головы их – Тогда в Ложу Тики закрыт мой путь… Вместе склеить всех поможешь – И будем мы почётными гостями!
277 Коль главу нашёл, Сверху стой на ней, да подними. Доставишь целой – соберётся идол, Раз голова на теле.
1095 Вот яйцо. Это знак полноправного участника в Ложе сей.
287 Если голову взял уже, Зависни над телом Тики, С квадратом жми кнопку – И груз опустится.
1102 Исход раньше такой не видал. Не знак ли это злых духов?
318 А ты – дракончик, кто яйца тут искал? Уж видел я – парнишка подозрительный С одним пробегал.
1054 Эй, там есть ещё другой. Правда, он бегун… Может, я включил бы ускорение – С ним ты догонишь воришку!
517 Ты поймай вора, Чтоб не украл он что важного.
560 Сей люд в тюрьме давно ждут.
328
551 Ну наконец-то можно к шару!
351 Шар тебя к великой Ложе Тики в эфир отнесёт! Так вперёд, коль желаешь.
1013 Спешу на вечерний праздник в Ложу Тики я, А портал ко мне домой исчез вскоре. Может, он снова заработает, Вышли б драконы из яиц.
362 Портал работает мой наконец! Увидимся, в Ложе Тики там.
*UPD* – +277, +1095 but nobody came
Сообщение отредактировал aleksusklim - Пятница, 28.10.2016, 23:23
Две разные копипасты описания формата, как хранятся тексты Spyro3. Сделаны в разное время для разных людей. Что-то актуально, что-то может быть уже нет. Публикую сюда.
Во-от. Так что пока в теории мой план более надёжен. Итак ещё раз, подробнее.
(далее под «4байта» я буду понимать 32-бит «word» / int)
Берём лист 88-ых объектов. Каждое первое 4байта объекта – локальный указатель на 12 байт (три раза по 4байта) доп-данных. Если последние 4байта не равны «FF000000» – отбросить объект. Далее пойти вниз, по списку указателей на «локальные указатели». Если какой-то из них показывает на 4байта после 12 байт доп-данных, отметить объект как хороший (ещё можно на следующие 4 байта тоже ждать указатель, ещё не знаю, даст ли эта дополнительная строгость отсечение какого-нить мусора). Затем выкинуть все «нехорошие» объекты. Потом читать для каждого всё, что за доп-данными, запоминая первый и последний указатели на строки. Предположение в том, что это всё ЦЕЛИКОМ текст – какие-то реплики. Важно начало и максимальный размер этой области.
Хотя все реплики сами по себе нам тоже понадобятся. Для каждого объекта нужно знать следующее: • номер WAD_SUB. • порядковый индекс объекта (позиция в 88-списке). • его 12 байт (ну 8 на деле) доп-данных, и всё что это может нам дать. • общее количество его фраз, включая все пустышки. • имя объекта Теперь для каждой его фразы: • указатель на то, где расположен непосредственный локальный указатель на эту строку. • индекс в листе указателей, который отвечает за указатель из предыдущего пункта. • значение первого байта текста, либо ноль – если это первая фраза = само имя объекта. • столько байт в начале строки, предшествующие настоящему тексту (всё это придётся куда-то запоминать, потому что этот кусочек должен остаться привязан к переведённой строке, где бы она не оказалась). • вопрос, нужно ли запоминать [номер] реплики по нашему кривополученному списку соответствия озвучкам? Пока я технического смысла в этом не вижу. С другой стороны, номер позволяет легко идентифицировать каждую строку. Однако как я помню, его очень трудно получить. А ещё, если наше техническое дело-таки дойдёт до озвучики, нам понадобится не только ребилдинг STR (можно считать что уже solved), но и какое-то сопоставление всех озвучек всем текстам, и очень желательно, чтобы оно было полностью автоматическим. Вот чувствую, что там уже номер реплики понадобится как ни крути…
Так вот. Я думал что-то вроде по одному .txt документу на подуровень, скажем, следующей структуры:
12) Zoe - text 1 - text 2 - - text 3 45) Hunter - do it? - yes - no 62) - go off - come on in - 116) Zoe - hint
То есть тут по порядку появления перечисляются говорящие объекты, в формате «номер-скобка-имя» (игнорим пробелы здесь и везде), за которым по строкам перечислены все его реплики в том порядке, в каком следуют указатели на них, в формате «дефис-текст», причём если реплика пустая, то будет просто дефис (ну нам ведь не понадобятся нигде тексты состоящие из одних пробелов или пустых строк?). Все прочие переносы или вхождения, не удовлетворяющие формату – игнорируются. Такой файл вполне себе будет пригоден для ручного редактирования.
Но это не единственный «output» алгоритма, потому что всё то, что я сказал, что нужно знать и запомнить – придётся где-то хранить, и очень желательно, чтобы не здесь. Потому что индексы, байты и указатели – критичная штука, которую мы менять не собираемся, и она не должна быть редактируемой вот так просто. Поэтому придётся в каком-то ещё формате хранить всю кучу данных, единожды извлечённый из, что важно, оригинального WAD.WAD.
Далее тексты будут вставляться, как я сказал, алгоритмом рюкзака, причём сразу для всей игры для всех подуровней. Считываются все строки текущего уровня, а потом перебором разбрасываются по тем имеющимся областям, где когда-то был оригинальный текст.
Ну алгоритм примерно такой (работает математически на цифрах, а не на самих данных): рекурсивная функция, которая пытается разместить текущую строку в доступное свободное место (строки заранее отсортированы по убыванию длины) – если поместилась, то рекурсия на следующую строку; если нет – пытаться положить текущую строку в следующее свободное место, и так далее; если всё равно не удалось – выйти из рекурсии выше, чтобы породившая рекурсия отвергла эту ветку и пыталась далее. А ещё нужно запоминать самый глубокий провал, чтобы в случае, если разместить всё не получилось – выкинуть эту строку (в EXE), а алгоритм повторить без неё.
Итак, если всё вернулось удачно – раскидываем строки как рюкзак приказал. Причём здесь очень аккуратно нужно будет с указателями работать, чтобы всё плотненько и корректно запихать. Если же не всё гладко – ломаем указатель на неудобные строчки в оконечном листе, каждую из них копируем в очередное (ну начиная с какого-то) место в EXE, естественно, запоминая смещение после неё, для копирования других таких. Вычисляем абсолютный указатель на неё в EXE, и вписываем его вместо локального в сам объект.
Ну вроде как всё верно. В итоге, предположим, мы ни в чём себе не отказывали, и реплики у нас дай бог. Тогда некоторые из них улетят в EXE, но при этом же освободят своё место другим строкам! А рюкзак гарантирует, что оно будет использовано максимально. То есть по факту место в EXE, мне кажется, не так уж быстро будет кончаться. И туда всё поместится. Вообще все, что мы захотим.
С именами и того прикольней, можно таких как Зоя и Хантер отдельной бригадой в EXE заточить, и они априори отдадут дополнительные байты тексту. Плюс та фишка с FF000000-пустыми репликами. Их тоже для верности можно в EXE кидать, чё б нет, всего 4 байта.
Но к сожалению, это не всё. Я умолчал о перекодировании нашего текста по таблице соответствия, а также о чистке текста. Чистка – например замена тире на дефисы (физически символ), три точки подряд на многоточье, двойные пробелы на один пробел. Этот надо как-то формализовать, и желательно не в коде программы, чтобы менять можно было.
Я подумал о чём-то вроде списка замены. Этот как бы таблица с двумя столбцами, обрабатываемая построчно; в каждой ячейке – подстрока (может быть более одного символа). В целевой строке ищется первая подстрока: если не найдена – идём дальше по списку. Как только что-то совпало – делаем замену этого содержимым второго столбца, и сбрасываем всю обработку в начало (так куда надёжнее, хотя наверное можно что-то оптимизировать). А ещё надо как-то из потенциального зацикливания выходить…
Только пока у меня нет идей, как эффективно (для использования и изменения) хранить эту таблицу. Тут уже .ini структура A=B, C=D не прокатит, потому что сами «B» и «D» – бинарные (особенно для Spyro3), которые могут содержать символ переноса строки или ещё что похуже.
Считывает файлы в таком формате (все числа целые положительные): «количество участков памяти», «список размеров всех участков»; «количество размещаемых строк», «список размеров строк (включая терминирующий ноль каждой)». Если обработка успешна – пишет в выходной файл для каждой строки (в том же порядке) номер участка, куда её рекомендуется всунуть (участки нумеруются с нуля); либо = «-1», вместо индекса, если данную строку лучше вытащить в EXE. Входной файл передаётся либо в первом аргументе, либо считывается прямо со входного потока; выходной файл – либо во втором аргументе, либо просто пишет на консоль.
bagpack_test.bat – запуск на файл, in.txt – пример. В архиве две версии бинарника, сделанные на разных компиляторах.
Программу можно прикрутить как есть к будущей системе внедрения строк; можно и переписать заново. И кстати, я не уверен в полной правильности его работы, я плохо проверял результаты. На вид работает…
Начнём с первого файла, «Wad_112-4.wad». (Если что, это суб-субфайл)
По смещению 48 Нужно считать указатель. Это – относительный указатель, он показывает, на сколько байт от текущей позиции (от самого себя) нужно сдвинуться вперёд (или назад, но такого не бывает). Эффективно, если на самом деле СЧИТЫВАТЬ указатель – то текущая позиция уже будет на 4 байта впереди, поэтому от указателя надо отнять 4. Если же файл уже в памяти (а это значительно быстрее, чем по 4 байта с диска читать…) – то просто инкремент настоящего указателя на его же значение. Таким образом, если там число «4» – то оно показывает прямо на следующее же число.
Так вот! По смещению 48 – относительный указатель. Он показывает на следующий относительный указатель. Я это называю «прыжок». Совершить прыжок – значит считать текущее значение и продвинуться на него вперёд.
После двенадцатого прыжка курсор оказывается на относительном указателе, который по совместительству показывает размер области с объектами. Это – общая выделенная под них память, но заранее инициализированы не все. Количество реально существующих объектов записано в следующем же целом числе – в данном случае, это «5» (на скриншоте – не закрашено, перед жёлтой областью).
Каждый объект – это структура по 88 байт, они следуют прямо друг за другом. То есть дальше можно уже считывать первый объект.
Сейчас в каждой такой структуре нас интересует только первое целое число – это абсолютный указатель на дополнительные данные для этого объекта. Он всегда ненулевой.
Абсолютный указатель означает, что отсчёт ведётся от начала виртуального файла; но не всегда физически от самого бинарного файла; на в данной ситуации, поскольку это уже извлечённый суб-субфайл уровня – указатели прямо фактически от его начала.
Теперь нужно перейти по каждому из них по очереди, чтобы посмотреть на дополнительные данные объекта:
– я покрасил дополнительные данные в цвет того объекта, которому они принадлежат. Мы почему-то считаем, что эти данные всегда занимают не менее 12 байт, так что для простоты можно считать, что они всегда 12, просто располагаются не подряд.
Ещё раз, на эти данные я попал, перейдя по абсолютному указателю в первом целом числе структуры каждого объекта.
Из всех объектов меня интересуют только те, у которых в дополнительных данных третье число, то есть байты с 9 по 12 – равно «255», причём как четырёхбайтное целое, эффективно FF000000. Иными словами, байт номер 9 равен 255, а байты 10, 11, 12 – нулю.
Из всех пяти объектов только один удовлетворяем этому условию, а все остальные – не содержат текста, и должны игнорироваться. Посмотрим на саму структуру его, выше:
– здесь выделен именно первый абсолютный указатель на дополнительные данные, являющийся по факту файловым смещением, на которое нужно перейти.
Далее, раз мы знаем, что дополнительные данные оканчиваются на FF000000, то последующие абсолютные указатели за дополнительными данными – это указатели на строки.
Первый – самый простой, это имя объекта. Простой указатель на начало строки, а все строки начинаются со смещения, которое кратно четырём. А строки оканчиваются нулевым байтом. Это означает, что строки, следующие вплотную друг за другом – на самом деле могут быть разделены более чем одним нулевым байтом. Строка дополняется столькими нулями, пока смещение следующего за ней символа не станет кратно четырём. Например если в строке всего один символ – то после него будут 3 нуля, чтобы суммарная длина делилась на 4 без остатка. Для строки из двух символов – два нуля; для трёх символов – всего один настоящий ноль. А вот если длина уже кратная четырём – то в файле будут выделены все четыре нулевых байта, чтобы строки не слиплись.
Зная это, получаем имя объекта – строка по первому абсолютному указателю, до первого нулевого байта. Но не совсем: лучше засчитать в пользу строки и все дополнительные нулевые байты по описанному расчету, чтобы точно получить смещение, где должно ожидаться начало следующей строки.
– на скриншоте после синих данных сверху – раскрашены указатели на строки. Соответствующие им тексты закрашены тем же цветом ниже. (А розовое в самом низу – дополнительные данные последнего объекта, в котором нет текста.)
Но лишь имя объекта является простой строкой! Все его реплики – управляющие строки. Каждая управляющая строка начинается с байта, в котором записано общее количество управляющих байт в начале этой строки. Его нужно эффективно пропустить, причём первый байт сам по себе считается управляющим. Таким образом, если на самом деле управляющих байт нет, то первый байт будет равен единице, а сразу после него – сама строка. Однако обычно управляющих байт там может быть от 2 до 7 и более. Причём они считаются входящими в саму строку при расчете количества дополнительных нуле на конце.
Если первый управляющий байт строки равен 255, то это означает, что строка «пустая». Собственно, байт = 0 тоже формально сработает (нет управляющих, значит это и есть начало строки, но ноль её же и завершает). Пустые строки в объектах допустимы, и часто встречаются между репликами. Но они забирают по 4 байта на свою длину, и следующая строка начнётся после этого «255» (опять же как int).
Мы будем считывать подряд указатели на строки, до тех пор, пока последующий вдруг не перестанет показывать ровно на то место, где ожидается начало следующей строки. Если не совпало – значит строки кончились, и можно идти искать следующий объект.
На скриншоте: красная простая строка – имя объекта. Далее две непустые управляющие строки – желтая и зелёная, хотя в обеих управляющий байт всего один. За ними – ещё аж шесть пустых строк, отмечены тусклыми цветами. Правда, последняя не совсем понятно почему, но начинается с «0100…» – управляющий байт есть, но первым же символом строки является нулевой байт. Думаю, это можно считать эквивалентом пустой «FF00…» строки тоже (хотя может потом придётся поменять).
Последний указатель – число «4» – очевидно не показывает на последующую память, а значит – больше строчек в объекте нет.
Что должен сделать алгоритм? Получить всё место, отведённое под все строки объекта – прямо всё-всё, большим куском. Однако, все управляющие последовательности в начале каждой управляющей строки нужно сохранить отдельно, чтобы не потерять.
Далее, зная индекс исходной строки, и поданного на вход программы текста перевода – разместить в памяти переведённые строки, не забыв дописать в их начала правильные управляющие последовательности.
Строки могут не начинаться со смещения, кратного четырём. То есть разделять их можно всего лишь одним нулевым байтом, получая таким образом дополнительное пространство. Более того, все пустые строки (которые выводить не нужно, и в переводе их не будет) всех объектов – можно схлопнуть в единые 4 байта, разместив их где-нибудь. То есть все указатели можно поменять так, чтобы они указывали на одно и то же число 255, эффективно получая ещё по четыре символа с каждой пустой строки.
И разумеется, программа должна корректно поменять все указатели на строки, чтобы они попадали в начала их управляющих последовательностей. На выходе получаем сохранённый файл, в котором и строки перезаписаны, и указатели изменены.
Бонус! «Wad_104.wad» Как парсить субфайлы уровней, а не суб-субфайлы подуровней. На самом деле всё просто, нужно только в алгоритме сделать поддержку того, что абсолютные указатели отсчитываются не от фактического начала файла. А ещё проще – загрузить в память нужный косок файла, и пусть алгоритм работает как обычно, если он конечно всё читает сразу из своей памяти как из массива данных.
Нужно перейти по смещению 24 – это указатель на первый суб-субфайл подуровня. Его размер – в следующих четырех байтах, и весь субфайл можно сразу считать в память; но можно и игнорировать размер. В самом суб-субфайле – вести себя как в предыдущем алгоритме: перейти к смещению 48, сделать 12 прыжков… Но все абсолютные указатели будут именно относительно начала суб-субфайла в памяти.
Указатель на начало следующего субфайла – на 16 байт дальше, чем указатель на данный (цветные на скриншоте). По факту, это смещения 24, 40, 56, 72. Остановиться нужно на том, указатель по которому нулевой.
А в этом файле текста уже гораздо больше, вот например один из объектов:
Выделены 12 дополнительных байт, за которыми следуют указатели на имя и тексты; В трёх видимых текстах количество управляющих байт равно 4, 4, и 6. but nobody came
Файл «0» – это некорректная попытка, я там что-то нарушил. Но получилось прикольно. Там FreezeCheat, так что нужно нажать и отжать паузу. С Бентли не говорить, а то вылетает; надо сначала отойти от него. Файл «1» – это уже как надо. Я расширил ту зону, что следует после списка объектов. То есть я укоротил список до, хм… 3+10 штук, и всё былое пространство – внёс как в «дополнительные данные», которые просто не будут использоваться, но ни на что не влияют. Как видно, игра не вылетела. Она работает стабильно. Разве что, при создании нового объекта – если под него «нет места» – то он тупо не создаётся. Из чего следует, что мы, в принципе, вполне можем взять себе несколько штучек… (учитывая что в оригинале там сотни!) Каждый объект даёт нам +88 байт на строки или ещё что-либо. Например, потом надо попробовать вытащить в «последний объект» те строки, что предназначены для меню Help. Того гляди, и в EXE даже не придётся ничего писать.
Конечно, нельзя забирать слишком много объектов. Знаете, что будет, если места не хватит на Спаркса!? …да ничего страшного. Просто Спаркс не появится, и Спайро останется с одной жизнью. Ну, я к тому, что мы не можем знать точно, сколько пустого буфера под объекты реально необходимо уровню. Пожалуй, следует написать программу, высчитывающую количество живых объектов в реальном времени, тем более что я по-моему даже знаю, где у них там бит alive…
А вот преимущественно для актёров: (текст вложен в архив)
Установка: 1) Распакуйте архив куда-нибудь на жёсткий диск. (Для будущей стабильности убедитесь, что в пути нет всяких специальных символов.) 2) Запустите «install_settings.reg» и подтвердите изменение реестра. (Если не получается, то попробуйте открыть командную строку cmd.exe и написать туда «reg import [пробел]» и перетащить этот файл в консоль, выполнить).
Настройка: 1) Запустить «ePSXe.exe» 2) Выбрать пункт меню «Config > Game Pad > Port1 > Pad1». Здесь можно переназначить кнопки управления. 3) В пункте меню «Config > Video» можно выбрать плагин DirextX или OpenGL. Нажатие Configure – расширенные настройки плагина, самое важное – разрешение экрана вверху. Также есть Soft-плагин, настраиваемый кнопкой ниже. (Если ни один из предыдущих двух плагинов почему-то не работает, попробуйте переименовать «gpu.dat» в «gpu.dll» в папке «plugins\», и потом найдите Soft-плагин в верхнем списке.)
Запуск: 1) Пункт меню «File > Run ISO». 2) Выбрать нужный .iso или .bin файл. 3) Для паузы нажмите Esc. (Для продолжения – пункт «Run > Continue»). Чтобы изменить настройки, эмулятор придётся перезапустить.
Управление эмулятором: 1) Клавиша F1 – сохранение текущего состояния в активный слот. Изначально активен слот номер 1 (имена файлов .000). 2) Клавиша F2 – изменение активного слота с 1 по 5 и по кругу. Картинка предпросмотра будет показываться в верхнем правом углу экрана. 3) Клавиша F3 – загрузка состояния из активного слота. Эмулятор хранит отдельные пять слотов на каждую игру (они привязываются не к файлу-образу, а как бы к самой игре). 4) Клавиша F4 – включение и отключение ускоренного воспроизведения игры, соответствующая иконка отображается справа. 5) Клавиша F7 – переключение на Soft плагини обратно. В настройках по умолчанию, D3D и GL плагины развёрнуты на весь экран, а Soft работает в окне, поэтому F7 эффективно переводит игру в оконный режим; тем не менее, возврат в главное окно всё равно через Escape. 6) Клавиша F8 – снять скриншот экрана. Снимки будут копиться в папке «snap\». 7) По умолчанию графические опции настроены на цифры 1-6. Клавиша 1 активирует панель управления плагином (строка сверху), 2 – включает подсказки. Далее цифры 5-6 меняют текущий активный пункт, а 3-4 – включают или выключают его. Например, первый же пункт управляет ускорением и замедлением игры. 8) Другие клавиши Fx, и цифры 7,8,9,0 – лучше не нажимать.
Контроллер первого игрока по умолчанию: (изменяется в меню) 1) Стрелки вверх-вниз-вправо-влево – стрелки на клавиатуре; 2) Крест – RCtrl, Круг – Num0, Квадрат – RShift, Треугольник – End; 3) Старт – Space, Селект – LCtrl. 4) L1 – Delete, R1 – PageDown, L2 – Insert, R2 – PageUp.
Основные действия кнопок в игре Spyro2/3: 1) Крест – прыжок. Крест в прыжке – полёт. 2) Круг – атака огнём или снарядом. 3) Квадрат – бег и атака рогами, также под водой. 4) Треугольник – зажать на земле – осмотреться/прицелиться; в прыжке – вертикальный удар вниз; в полёте – взмах вверх с приземлением. 5) Старт – пауза, Селект – сразу атлас. 6) L2, R2 – вращение камеры; L1/R1 – центрирование камеры. 7) Техника дальних перелётов: квадрат для разгона; на самом краю – с квадрата удерживать крест и кнопку вперёд, отпустить квадрат; в верхней точке прыжка – быстро отпустить и зажать крест ещё раз, уже можно просто рулить; перед приземлением – в конце держать вперёд и нажать треугольник в самый точный момент, не слишком рано, но и не вплотную к целевой площадке. 8) Большие враги убиваются кнопкой круг, маленькие – кругом или квадратом, металлические – только квадратом; Иногда нужно ударить сверху треугольником. 9) Текущее здоровье показывает стрекоза: жёлтый цвет – 3 жизни, синий – 2, зелёный – 1, отсутствие стрекозы – 0. Здоровье пополняется при уничтожении мелких животных, из которых вылетают бабочки. but nobody came
Хантер от испуга выронил охотничий лук и обернулся.
– Спайро? О, ты тут! Зацени.
Он поднял оружие и вставил в него одну из стрел.
– Видишь наконечник? Это Профессор придумал. Там магнитная пыль заряженных камней Харрикоса, и порох с фабрики фейерверков. Я уже пробовал! Напрочь ломает их нейтронную турбину и систему навигации.
– И-и?..
– Тихо, одна летит…
Вдали показалось НЛО, стремительно приближающееся к напарникам. Хантер пригнулся, пробежал вперёд, споткнулся, ещё раз поднял лук с земли, и затаился возле куста.
Дракон продолжал стоять и смотреть на выражение лица а-ля «не пали». Когда тарелка пролетела над ними, Хантер вышел из укрытия, натянул тетиву и выстрелил.
Он промахнулся. Однако стрела, пролетев через кольца, оставляемые двигателем летающей тарелки, внезапно взорвалась. В воздухе возник разноцветный салют, а машина потеряла управление.
Дымящееся НЛО накренилось к земле, его крыша отскочила, а оттуда выпрыгнула белая овца. Вскоре она раскрыла парашют, и плавно опустилась к земле. Однако ветер подул в правильную сторону.
– Яйцо!!
Хантер направил лук со второй стрелой прямо на неё.
– Бе-е-е!
Вдалеке послышался звук от разбившегося летательного аппарата.
– Там было яйцо!?
– Бе-е-е!!
Хантер приблизился к ней в упор, замер на секунду, а потом грустно опустил оружие.
– Ладно, пошла вон.
Спайро моргнул от удивления. Глядь – овечки уже нет.
– И почему ты её отпустил?
– Пустая. Будь у неё яйцо, под ТАКИМ не соврала бы!
Гепард нацелился на нос дракона. Спаркс прожужжал что-то невнятное, а Спайро просто обошёл вокруг. Затем посмотрел в небо на исчезающий след.
– Ну а если бы яйцо там было?
– Поэтому мне и нужен ты! Я буду сбивать тарелки, а ты – спасать из обломков драконьи яйца. Вон ещё трое, готовься!
На горизонте появился штурмовой овечий отряд. Их предводитель летел на тарелке, у которой снизу был шлюз для захвата объектов.
Когда Хантер зарядил очередную стрелу, овцы изменили построение и совершили перекрёстный маневр. Спаркс хотел было прожужжать «Сложность: *****», но Спайро уже помчался вперёд.
Вскоре одна тарелка была подбита.
– Вали главного!
Спайро побежал в направлении чёрного следа, а Хантер по его совету – совершил перебежку на открытую местность, потому что вражеский отряд, видимо, решил отступить.
Когда дракон добрался до рухнувшего НЛО, пилота уже не было. Однако, там действительно лежало драконье яйцо! Он вытащил его и побежал прятать.
Раздался грохот. Овечий командир был подбит, а его напарник – благополучно покинул зону досягаемости стрел. Спайро побежал ко второму потенциальному яйцу.
Там уже стоял Хантер, открывший кабину летающей тарелки. Внутри лежало… яйцо?
– Это… а что с ним?
Объект был размером с драконье яйцо, но странной крапчатой окраски. И был словно весь в перьях. Хантер наклонился и принюхался.
– Может, палкой в него потыкать…
Оно шевельнулось! Спаркс облетел его кругом в негодовании.
– Зоя! Ты тута? Зоя, появись-ка на секунду!..
Спайро искал взглядом полупрозрачную звезду.
– Так это существо!
Фея оказалась позади дракона. Она взмахнула палочкой, и наградила субъект магическим зарядом. Зверюшка приподнялась и открыла два больших глаза. Спайро вдруг осенило.
– Да это же со…
– г.д.е.?
Она пошла на контакт. Хантер решил ответить.
– Ну, эту трассу Спаркс частенько зовёт…
– г.о.д.?
Зоя удивилась.
– Год? Так две тысячи…
– о.х..
Она склонилась, но вскоре встала во весь рост.
– А ты тут, потому что…
– о.в.ц.ы.
Хантер перевёл взгляд на небо.
– Кстати, о них.
– в.п.е.р.ё.д.
Она взмахнула крыльями и вылетела из тарелки. Спайро вопросительно посмотрел на Хантера, а тот приготовил свой лук.
– н.у.?
– В смысле, стрелять? И правда, ну…
Стрела пролетела очень удачно, попав в самый центр построения пяти НЛО. Взрыв поразил несколько из них, и вот небо окрасилось в чёрные полосы, дымовые кольца и катапультирующихся овец.
– с.к.о.р.е.й.!
– Да, но мы собираем…
– я.й.ц.а.
Дракон остановился на секунду, потом кивнул и побежал к ближайшей упавшей овце. Пусто.
– с.ю.д.а.!
Хантер видел, что она вспорхнула наверх, откуда хорошо видны места падения тарелок.
– А ведь неплохо придумано!
Тем более, что он уже успел подбить их все.
Поднимая последнее яйцо, Спайро осторожно задал вопрос.
– Так, ты теперь…
– д.а.
– О, хорошо, просто… Просто у нас есть на примете ещё где…
– и.д.ё.м.
Спаркс даже стал лететь ближе к ней, чем к дракону. Хантер раскрыл рот, что бы что-то сказать, но вовремя понял, что не сможет выразить свою мысль достаточно кратко. Он шёл молча всю дорогу, и смотрел на блестящие наконечники своих стрел.
– Хм. Придётся привыкнуть.
Зоя, наконец, перестала висеть в воздухе на одном месте, и просто исчезла. but nobody came
Сообщение отредактировал aleksusklim - Понедельник, 07.11.2016, 18:02