Skip to content
This repository has been archived by the owner on Aug 20, 2024. It is now read-only.

Commit

Permalink
rewrite starting positions again (generates starting positions first,…
Browse files Browse the repository at this point in the history
… doodads second)
  • Loading branch information
malytomas committed Dec 11, 2023
1 parent 7a6cb61 commit 2c7e996
Show file tree
Hide file tree
Showing 9 changed files with 179 additions and 145 deletions.
7 changes: 5 additions & 2 deletions doodads/ores/aether.doodad
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ package = unnatural/base/ores/ores.pack
prototype = unnatural/base/ores/aether_deposit.proto

[generating]
count = 3
count = 5
priority = 15

[requirements]
radius = 40
buildable = true

[starting]
distance = 200, 200
distance = 500, 500
count = 0, 0

[preview]
height = 100
7 changes: 5 additions & 2 deletions doodads/ores/crystals.doodad
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ package = unnatural/base/ores/ores.pack
prototype = unnatural/base/ores/crystals_deposit.proto

[generating]
count = 4
count = 10
priority = 14

[requirements]
radius = 40
buildable = true

[starting]
distance = 200, 200
distance = 500, 500
count = 0, 0

[preview]
height = 100
9 changes: 6 additions & 3 deletions doodads/ores/metal.doodad
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ package = unnatural/base/ores/ores.pack
prototype = unnatural/base/ores/metal_deposit.proto

[generating]
count = 30
count = 20
priority = 10

[requirements]
radius = 40
buildable = true

[starting]
distance = 50, 200
count = 2, 10
distance = 200, 300
count = 2, 3

[preview]
height = 50
7 changes: 5 additions & 2 deletions doodads/ores/oil.doodad
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,8 @@ radius = 40
buildable = true

[starting]
distance = 150, 150
count = 0, 0
distance = 300, 500
count = 1, 1

[preview]
height = 100
179 changes: 106 additions & 73 deletions sources/doodads.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@
#include <cage-core/ini.h>
#include <cage-core/logger.h>
#include <cage-core/math.h>
#include <cage-core/mesh.h>
#include <cage-core/spatialStructure.h>
#include <cage-core/string.h>

namespace unnatural
{
void previewMeshAddPoint(Mesh *msh, Vec3 pos, Vec3 up, Real height);

namespace
{
void loadDoodad(const String &root, const String &path)
Expand Down Expand Up @@ -49,6 +52,9 @@ namespace unnatural
d.radius = ini->getFloat("requirements", "radius", d.radius.value);
d.buildable = ini->getBool("requirements", "buildable", false);

if (ini->itemExists("preview", "height"))
d.previewHeight = ini->getFloat("preview", "height");

ini->checkUnused();
if (!(d.temperature[0] < d.temperature[1]))
CAGE_THROW_ERROR(Exception, "invalid temperature range");
Expand Down Expand Up @@ -105,10 +111,56 @@ namespace unnatural

void placeDoodads(DoodadDefinition &doodad)
{
std::vector<uint32> candidates;
candidates.reserve(tiles.size() / 10);
std::vector<uint32> spCounts; // count doodads for each starting position
spCounts.resize(startingPositions.size(), 0);

const auto &tryPlace = [&doodad, &spCounts](uint32 c) -> bool
{
if (doodad.startsDistance[0] > 0)
{
for (uint32 s : startingPositions)
if (distance(tiles[s].position, tiles[c].position) < doodad.startsDistance[0])
return false; // doodad too close to a starting position
}

if (doodad.startsDistance[1] > 0)
{
for (auto ss : enumerate(startingPositions))
{
if (distance(tiles[*ss].position, tiles[c].position) > doodad.startsDistance[1])
continue;
if (spCounts[ss.index] >= doodad.startsCount[1])
return false; // too many doodads close to a starting position
}
}

Tile &t = tiles[c];
spatialQuery->intersection(Sphere(t.position, doodad.radius));
if (!spatialQuery->result().empty())
return false; // would overlap with already existing doodad

t.buildable = false;
t.doodad = &doodad;
doodad.instances++;
spatialStructure->update(c, Sphere(t.position, doodad.radius));
spatialStructure->rebuild();

if (doodad.startsDistance[1] > 0)
{
for (auto ss : enumerate(startingPositions))
{
if (distance(tiles[*ss].position, tiles[c].position) > doodad.startsDistance[1])
continue;
spCounts[ss.index]++;
}
}

return true;
};

// generate initial candidates
std::vector<uint32> candidates;
candidates.reserve(tiles.size() / 10);
for (auto it : enumerate(tiles))
{
if (it->doodad)
Expand All @@ -125,8 +177,12 @@ namespace unnatural
}

// shuffle the candidates
for (uint32 &c : candidates)
std::swap(c, candidates[randomRange(0u, numeric_cast<uint32>(candidates.size()))]);
const auto &shuffle = [&candidates]()
{
for (uint32 &c : candidates)
std::swap(c, candidates[randomRange(0u, numeric_cast<uint32>(candidates.size()))]);
};
shuffle();

// place doodads
for (uint32 c : candidates)
Expand All @@ -135,32 +191,59 @@ namespace unnatural
break;
if (randomChance() > doodad.chance)
continue;
Tile &t = tiles[c];
spatialQuery->intersection(Sphere(t.position, doodad.radius));
if (!spatialQuery->result().empty())
continue; // would overlap with already existing doodad
t.buildable = false;
t.doodad = &doodad;
doodad.instances++;
spatialStructure->update(c, Sphere(t.position, doodad.radius));
spatialStructure->rebuild();
tryPlace(c);
}
std::erase_if(candidates, [](uint32 c) { return !!tiles[c].doodad; });

// place additional doodads to meet minimum requirements for starting positions
for (uint32 player = 0; player < startingPositions.size(); player++)
{
uint32 &myCount = spCounts[player];
if (myCount >= doodad.startsCount[0])
continue;
shuffle();
const Vec3 myPos = tiles[startingPositions[player]].position;
for (uint32 c : candidates)
{
const Real dist = distance(tiles[c].position, myPos);
if (dist < doodad.startsDistance[0] || dist > doodad.startsDistance[1])
continue;
tryPlace(c);
if (myCount >= doodad.startsCount[0])
break;
}
}
}

void writeDoodads()
{
Holder<File> f = writeFile(pathJoin(baseDirectory, "doodads.ini"));
for (Tile &t : tiles)
{
if (!t.doodad)
continue;
assetPackages.push_back(t.doodad->package);
f->writeLine("[]");
f->writeLine(Stringizer() + "prototype = " + t.doodad->proto);
f->writeLine(Stringizer() + "position = " + t.position);
f->writeLine("");
Holder<File> f = writeFile(pathJoin(baseDirectory, "doodads.ini"));
for (Tile &t : tiles)
{
if (!t.doodad)
continue;
assetPackages.push_back(t.doodad->package);
f->writeLine("[]");
f->writeLine(Stringizer() + "prototype = " + t.doodad->proto);
f->writeLine(Stringizer() + "position = " + t.position);
f->writeLine("");
}
f->close();
}

{
Holder<Mesh> msh = newMesh();
for (Tile &t : tiles)
{
if (!t.doodad)
continue;
if (!valid(t.doodad->previewHeight))
continue;
previewMeshAddPoint(+msh, t.position, t.normal, t.doodad->previewHeight);
}
msh->exportFile(pathJoin(baseDirectory, "doodads-preview.obj"));
}
f->close();
}

bool logFilterSameThread(const detail::LoggerInfo &info)
Expand Down Expand Up @@ -219,57 +302,7 @@ namespace unnatural
for (DoodadDefinition &doodad : doodadsDefinitions)
placeDoodads(doodad);

for (DoodadDefinition &doodad : doodadsDefinitions)
{
if (doodad.instances < doodad.startsCount[0])
{
CAGE_LOG_THROW(doodad.name);
CAGE_THROW_ERROR(Exception, "doodad minimum starting count cannot be satisfied");
}
}

writeDoodads();
printStatistics();
}

void filterStartingPositionsByDoodads(std::vector<uint32> &positions)
{
// filter by minimum distances
{
Holder<SpatialStructure> spatStruct = newSpatialStructure({});
for (auto it : enumerate(tiles))
if (it->doodad)
spatStruct->update(it.index, Sphere(it->position, max(it->doodad->radius, it->doodad->startsDistance[0])));
spatStruct->rebuild();
Holder<SpatialQuery> spatQuery = newSpatialQuery(spatStruct.share());

std::erase_if(positions,
[&](uint32 i)
{
spatQuery->intersection(tiles[i].position);
return !spatQuery->result().empty();
});
}

// filter by starting counts
for (const DoodadDefinition &doodad : doodadsDefinitions)
{
if (doodad.startsCount[1] == m || doodad.startsDistance[1] == Real::Infinity())
continue;

Holder<SpatialStructure> spatStruct = newSpatialStructure({});
for (auto it : enumerate(tiles))
if (it->doodad == &doodad)
spatStruct->update(it.index, Sphere(it->position, it->doodad->startsDistance[1]));
spatStruct->rebuild();
Holder<SpatialQuery> spatQuery = newSpatialQuery(spatStruct.share());

std::erase_if(positions,
[&](uint32 i)
{
spatQuery->intersection(tiles[i].position);
return spatQuery->result().size() < doodad.startsCount[0] || spatQuery->result().size() > doodad.startsCount[1];
});
}
}
}
4 changes: 3 additions & 1 deletion sources/generator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ namespace unnatural
std::vector<Tile> tiles;
std::vector<DoodadDefinition> doodadsDefinitions;
std::vector<String> assetPackages;
std::vector<uint32> startingPositions;
const String baseDirectory = findTmpDirectory();
const String assetsDirectory = pathJoin(baseDirectory, "data");
const String debugDirectory = pathJoin(baseDirectory, "intermediate");
Expand Down Expand Up @@ -98,8 +99,8 @@ namespace unnatural
CAGE_LOG(SeverityEnum::Info, "generator", Stringizer() + "navmesh tiles: " + navmesh->verticesCount());
generateTileProperties(navmesh);
meshSaveNavigation(navmesh);
generateDoodads();
generateStartingPositions();
generateDoodads();
}

void taskCollider(uint32)
Expand Down Expand Up @@ -382,6 +383,7 @@ import bpy
for (const Chunk &c : chunks)
f->writeLine(Stringizer() + "bpy.ops.import_scene.gltf(filepath = '" + c.mesh + "')");
f->writeLine(Stringizer() + "bpy.ops.import_scene.obj(filepath = '../starts-preview.obj')");
f->writeLine(Stringizer() + "bpy.ops.import_scene.obj(filepath = '../doodads-preview.obj')");
f->write(R"Python(
for a in bpy.data.window_managers[0].windows[0].screen.areas:
if a.type == 'VIEW_3D':
Expand Down
14 changes: 14 additions & 0 deletions sources/meshGeneration.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include "math.h"
#include "planets.h"

#include <cage-core/config.h>
Expand Down Expand Up @@ -187,4 +188,17 @@ namespace unnatural
cfg.padding = 6;
return meshUnwrap(+mesh, cfg);
}

void previewMeshAddPoint(Mesh *msh, Vec3 pos, Vec3 up, Real height)
{
const Vec3 s = anyPerpendicular(up);
const Vec3 t = cross(s, up);
const Vec3 a = pos + up * height + s * (height * 31 / 200);
const Vec3 b = pos + up * height - s * (height * 20 / 200) + t * (height * 30 / 200);
const Vec3 c = pos + up * height - s * (height * 20 / 200) - t * (height * 30 / 200);
msh->addTriangle(Triangle(pos, a, b));
msh->addTriangle(Triangle(pos, b, c));
msh->addTriangle(Triangle(pos, c, a));
msh->addTriangle(Triangle(a, c, b));
}
}
3 changes: 3 additions & 0 deletions sources/planets.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,14 @@ namespace unnatural
Vec2i startsCount = Vec2i(0, m);
Real radius = 5; // distance in which to prevent overlapping with other doodads
bool buildable = false;

Real previewHeight = Real::Nan();
};

extern std::vector<Tile> tiles;
extern std::vector<DoodadDefinition> doodadsDefinitions;
extern std::vector<String> assetPackages;
extern std::vector<uint32> startingPositions;

extern const String baseDirectory;
extern const String assetsDirectory;
Expand Down
Loading

0 comments on commit 2c7e996

Please sign in to comment.