Skip to content

Instantly share code, notes, and snippets.

@himika
Last active August 29, 2015 14:05
Show Gist options
  • Save himika/ec01678047182d2cb9e7 to your computer and use it in GitHub Desktop.
Save himika/ec01678047182d2cb9e7 to your computer and use it in GitHub Desktop.
近くに配置されているオブジェクトを、配列で一気に取得する関数
#include <skse.h>
#include <skse/GameForms.h>
#include <skse/GameData.h>
#include <skse/GameReferences.h>
#include <skse/GamePapyrusFunctions.h>
#include <list>
/* ==============================================================
scriptname HogeHoge hidden
; 近くに配置されているオブジェクトを、配列で一気に取得する
; afRadius ... 取得距離。この距離より短いものだけ取得。
ObjectReference[] GetCloseReference(float afRadius) global native
=================================================================*/
// グリッド状に配置されているセルの情報
// 大きさは skyrim.ini [General] uGridsToLoad に依存
class GridCellArray
{
public:
virtual ~GridCellArray();
UInt32 unk04;
UInt32 unk08;
UInt32 size;
TESObjectCELL** cells;
};
class HogeHoge
{
public:
// 近くに配置されているオブジェクトを、配列で一気に取得する
static VMArray<TESObjectREFR*> GetCloseReferences(float fRadius)
{
PlayerCharacter* player = *g_thePlayer;
GridCellArray* arr = (GridCellArray*)(*g_TES)->gridCellArray;
double fRadiusSquare = fRadius * fRadius;
// 隣接しているセルをすべて走査
typedef std::pair<TESObjectREFR*, double> Pair; // TESObjectREFR* と double の ペア
std::list<Pair> list;
int x, y;
for (x = 0; x < arr->size; x++)
{
for (y = 0; y < arr->size; y++)
{
TESObjectCELL* cell = arr->cells[x+y*arr->size];
if (cell->unk30 != 7) // 逆アセンブルで割り出した何かの数値。
continue;
// セルに配置されているTESObjectREFR*を走査
TESObjectREFR* ref = NULL;
int i = 0;
while (cell->objectList.GetNthItem(i++, ref))
{
if (!ref || ref == player)
continue;
if (ref->GetNiNode()) // NiNodeが取得できる == 3Dがロード済み
{
double dx = ref->pos.x - player->pos.x;
double dy = ref->pos.y - player->pos.y;
double dz = ref->pos.z - player->pos.z;
double d2 = dx*dx + dy*dy + dz*dz;
if (d2 < fRadiusSquare)
{
Pair pair(ref, d2);
list.push_back(pair);
}
}
}
}
}
// 距離が短い順でリストを並び替え
list.sort( [](Pair a, Pair b) {return a.second < b.second;} );
// list<Pair> を VMArray<TESObjectREFR*>に移し替える
VMArray<TESObjectREFR*> result;
if (list.size() > 0)
{
result.Allocate((list.size() < 127) ? list.size() : 127);
int n = 0;
while (list.size() > 0)
{
TESObjectREFR* ref = list.front().first;
list.pop_front();
result.Set(&ref, n++);
if (result.Length() >= 127) // Papyrusだと、配列は127までしか扱えない
break;
}
}
return result;
}
};
void RegisterPapyrusFunction()
{
VMClassRegistry* registry = (*g_skyrimVM)->GetClassRegistry();
REGISTER_PAPYRUS_FUNCTION(HogeHoge, GetCloseReferences, registry);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment