![]() |
Показать все 14 сообщений этой темы на одной странице |
HLFX.Ru Forum (https://hlfx.ru/forum/index.php)
- Half-Life SDK (https://hlfx.ru/forum/forumdisplay.php?forumid=8)
-- Это я глючу, или мой компьютер? (https://hlfx.ru/forum/showthread.php?threadid=1584)
Это я глючу, или мой компьютер?
Заранее прошу отнестись к этому вопросу сурьёзно, ибо непонятное поведение движка, наблюдаемое мной, никак не является следствием похмелья или других эффектов от злоупотребления различными нехорошими излишествами
Вопрос этот вызван следующей проблемой: есть класс, и в нём объявлен метод, который ничего не делает, кроме как загружает звук функцией PRECACHE_SOUND. Но когда этот метод выполняется (вызываю я его, естественно, из функции Spawn, т.к. загрузка разрешена только в момент спавна ентитей), то игра вылетает, а в консоль выводится сообщение, что невозможно загрузить МОДЕЛЬ. И в качестве имени модели выдаётся имя того самого звука, который я пытаюсь загрузить.
Ошибок типа "вместо PRECACHE_SOUND я вызвал PRECACHE_MODEL" или "попутал аргумент функции", в коде нету. Я проверил при помощи всяких алертов и т.п, и нет никаких сомнений, что вызывается именно функция PRECACHE_SOUND, и именно она является причиной вот такого сообщения.
И как вообще такое может быть? g_engfuncs я не трогал. Могла ли она как-то неявно перетащиться в другую область памяти так, что адрес pfnPrecacheSound заменился на адрес pfnPrecacheModel?
__________________
XaeroX Я думаю, кусок кода ничего не скажет, ибо он лишь вызывает PRECACHE_SOUND и всё. А вот насчёт неудачного указателя попрошу поподробней
В коде я в последнее время стал использовать операторы new/delete, мож, это из-за этого? (Но, опять же, они вызываются во многих местах, сюда этот код не влезет) Я чё-то и не предполагал, что в с++ нет контроля за памятью. Динамические массивы могут перемещаться куда хотят - это да, но чтоб и всё остальное...
Добавлено 14-11-2008 в 22:17:
Вообще, с подробной инфой тут проблематично, халфа и сорцы у меня на другом компе...
char *p = new char[32]; |
*(p + 1000) = 100; |
1 | typedef (blablabla) PFNPRECACHESOUNDPROC; |
2 | PFNPRECACHESOUNDPROC engineProc; |
3 |
4 | int Wrap_PrecacheSound(char *s) |
5 | { |
6 | MessageBox(0,"Precache sound", s, 0); |
7 | return engineProc(s); |
8 | } |
9 |
10 | ... |
11 |
12 | engineProc = g_engfuncs.pfnPrecacheSound; |
13 | g_engfuncs.pfnPrecacheSound = Wrap_PrecacheSound; |
__________________
Ну, что такое CRC я не знаю, но я тупо посчитал количество единичек в адресах. примерно вот так:
1 | int size = sizeof(g_engfuncs.BLABLABLA)*8; |
2 |
3 | for (int i = 0; i < size; ++i) |
4 | { |
5 | checksumm += ((int)g_engfuncs.BLABLABLA)&(1<<i); |
6 | } |
__________________
Не найдена модель блаблабла.wav. То есть именно тот путь, который я указываю в аргументе функции PRECACHE_SOUND.
Кхм, вообще-то контрольная сумма - вещь тоже не надёжная. Может, функции PRECACHE_SOUND & PRECACHE_MODEL поменялись местами, и сумма их адресов тогда останется неизменной. Я это говорю потому, что закомментировав вызов PRECACHE_SOUND, я наткнулся на ошибку "Не найден ЗВУК sound/models/dom_point.mdl", которая, очевидно, была вызвана функцией PRECACHE_MODEL("models/dom_point.mdl")
Так что я, пожалуй, проверю изменения каждого конкретного адреса в структуре g_engfuncs. Действительно, причина где-то на поверхности, и она, скорее всего, совершенно дурацкая...
А проблемка-то оказалась далеко не на поверхности.
Как мне удалось выяснить всякими там мессагами, алертами и т.п., в движке загрузка моделей/звуков производится то ли отдельным потоком, то ли ещё как-то так, короче, действительно модель начинает загружаться спустя определённое время после вызова PRECACHE_MODEL (даже g_ulFrameCount успевает доползти до 28-36). И при этом функции PRECACHE_blablabla не копируют свой аргумент в отдельный буфер, а используют всё тот же char* , который мы им передали. Так что если по тому адресу, куда указывает этот самый char* , будет другая строка, то мы получим вот такую ошибку.
В моём случае был указатель на буфер, общий для нескольких функций, которые писали туда имена всяких звуков, моделей и т.п.
Поэтому я стал использовать (char*)STRING(ALLOC_STRING(буфер)).
Отсюда следующий вопрос: А как движок обращается с буфером строк, в который пишется аргумент ALLOC_STRING? Если в него добавляются две одинаковые строки, то там и будут две одинаковые строки, или же одна заместит другую? (Потому что мне придётся юзать ALLOC_STRING довольно часто, но аргументы часто могут повторяться. Не вызовет ли это в конце концов переполнение памяти?)
__________________
XaeroX, да, действительно, в Half-Life наверное так же. Слишком уж редко это ALLOC_STRING вызывается, и нет смысла из-за столь малого количества памяти каждый раз перебирать весь пул или мутить хэш-таблицу...
Хотя, если глянуть с другой стороны, то зачем им было мутить загрузку ресурсов отдельным потоком в игре, в которой при смене карты выскакивает табличка "LOADING" и игровой процесс останавливается?
Мож они для того же понта и хэш-таблицу заюзали...
Дело не в потоке вовсе... Ресурсы грузятся очень хитро. Сначала создается список этих ресурсов. Потом он пересылается с сервера на клиент (даже в случае сингла, на локалхост). Потом клиент получает мессагу, читает ее и грузит все ресурсы. А отправка мессаги идет, видимо, асинхронно, отсюда и ощущение другого потока.
__________________
XaeroX, понятно, спасибо, учтём-с
У моделей, звуков и декалей общий буффер примерно на 2000 строк.
Разделение на зоны - только по старт-стоповым номерам.
Т.н. с 16 по 768 - модели, а с 768 по 1200 - звуки (это для примера).
Модельиндекс на сервере - это и есть возвращенный номер строки - пути к вашей моделке.
При старте вся эта волшебная шняжка шлется на клиент, но поскольку строк много, то делает это не за один кадр, а кадров за пять- шесть.
Но пять кадров на сервере, это кадров 30 на клиенте, отсюда и интересные значения g_ulFrameCount (PlayerThink вызывается с клиентским fps, в отличие от сервера).
Стринги, аллокнутые движком не высвобождаются автоматически и неоптимизируются в памяти никак, поскольку неизвестно будем ли мы только читать этот стринг или еще записывать.
Скажу только, что проблема с темп стрингами тянется еще с первокваки, но там её очень проблематично заметить, по причине бедности набора буилтинов. Я обычно выходил из положения создавая static стринги.
__________________
My Projects: download page
F.A.Q по XashNT
Блог разработчика в телеграме
C:\DOCUME~1\C4C5~1\LOCALS~1\Temp\a33328if(72) : see declaration of 'size_t'
Да, Дядя Миша, благодарствую, всё расписал фундоментально и по понятиям
Проблемку со строками этими я решил, создав дурацкий строковый буфер, работающий примерно как STL'овский map. В принципе, для моих целей сойдёт...
Временная зона GMT. Текущее время 19:19. | Показать все 14 сообщений этой темы на одной странице |
На основе vBulletin версии 2.3.0
Авторское право © Jelsoft Enterprises Limited 2000 - 2002.
Дизайн и программирование: Crystice Softworks © 2005 - 2024