Skip to content

Commit

Permalink
#2712 Added enemy connections option to creating a combat log
Browse files Browse the repository at this point in the history
  • Loading branch information
Wotuu committed Feb 8, 2025
1 parent 47fe3b0 commit 8964e57
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 12 deletions.
17 changes: 13 additions & 4 deletions app/Console/Commands/CombatLog/CreateMappingVersion.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class CreateMappingVersion extends BaseCombatLogCommand
*
* @var string
*/
protected $signature = 'combatlog:createmappingversion {filePath} {--mappingVersion=} ';
protected $signature = 'combatlog:createmappingversion {filePath} {--enemyConnections} {--mappingVersion=} ';

/**
* The console command description.
Expand All @@ -28,19 +28,28 @@ public function handle(CombatLogMappingVersionServiceInterface $combatLogMapping
{
$filePath = $this->argument('filePath');
$mappingVersionId = $this->option('mappingVersion');
$enemyConnections = (bool)$this->option('enemyConnections');

$mappingVersion = null;
if (is_numeric($mappingVersionId)) {
$mappingVersion = MappingVersion::findOrFail($mappingVersionId);
}

return $this->parseCombatLogRecursively($filePath, fn(string $filePath) => $this->createMappingVersionFromCombatLog($combatLogMappingVersionService, $filePath, $mappingVersion));
return $this->parseCombatLogRecursively($filePath,
fn(string $filePath) => $this->createMappingVersionFromCombatLog(
$combatLogMappingVersionService,
$filePath,
$mappingVersion,
$enemyConnections
)
);
}

private function createMappingVersionFromCombatLog(
CombatLogMappingVersionServiceInterface $combatLogMappingVersionService,
string $filePath,
?MappingVersion $mappingVersion = null): int
?MappingVersion $mappingVersion = null,
bool $enemyConnections = false): int
{
$this->info(sprintf('Parsing file %s', $filePath));

Expand All @@ -52,7 +61,7 @@ private function createMappingVersionFromCombatLog(

$hasMappingVersion = $mappingVersion !== null;

$mappingVersion = $combatLogMappingVersionService->createMappingVersionFromDungeonOrRaid($filePath, $mappingVersion);
$mappingVersion = $combatLogMappingVersionService->createMappingVersionFromDungeonOrRaid($filePath, $mappingVersion, $enemyConnections);
$this->info(
sprintf(
'- %s mapping version %s (%s, %d, %d enemies)',
Expand Down
47 changes: 46 additions & 1 deletion app/Helpers/ColorHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ function pad($v)
*/
function rgb2hex($r, $g, $b)
{
return '#' . implode('', array_map('dechex', array_map('round', [$r, $g, $b])));
return sprintf('#%02x%02x%02x', round($r), round($g), round($b));
}

/**
Expand All @@ -123,3 +123,48 @@ function randomHexColorNoMapColors(): string

return $result;
}

function pickHexFromHandlers(array $handlers, float $weight): string {
assert(count($handlers) > 1, 'Handlers.length <= 1!');

// If color is before the start or after the end of any gradients, return last known color
if ($handlers[0][0] >= $weight) {
return strtolower($handlers[0][1]);
} elseif ($handlers[count($handlers) - 1][0] <= $weight) {
return strtolower($handlers[count($handlers) - 1][1]);
} else {
// Color is in between gradients, determine which gradient it is
$color1 = null;
$color2 = null;
$scaledWeight = 0.0;

for ($i = 0; $i < count($handlers) - 1; $i++) {
$a = $handlers[$i];
$b = $handlers[$i + 1];

if ($weight >= $a[0] && $weight <= $b[0]) {
$color1 = hex2rgb($a[1]);
$color2 = hex2rgb($b[1]);

$gradientRange = $b[0] - $a[0];
$weightOnGradientRange = $weight - $a[0];
$scaledWeight = $weightOnGradientRange / $gradientRange;

break;
}
}

assert($color1 !== null, 'color1 === null!');
assert($color2 !== null, 'color2 === null!');

$invertedScaledWeight = 1 - $scaledWeight;

return strtolower(
rgb2hex(
round($color2[0] * $scaledWeight + $color1[0] * $invertedScaledWeight),
round($color2[1] * $scaledWeight + $color1[1] * $invertedScaledWeight),
round($color2[2] * $scaledWeight + $color1[2] * $invertedScaledWeight)
)
);
}
}
81 changes: 75 additions & 6 deletions app/Service/CombatLog/CombatLogMappingVersionService.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,18 @@
use App\Logic\CombatLog\SpecialEvents\MapChange;
use App\Logic\CombatLog\SpecialEvents\ZoneChange;
use App\Logic\Structs\IngameXY;
use App\Logic\Structs\LatLng;
use App\Models\Dungeon;
use App\Models\Enemy;
use App\Models\EnemyPatrol;
use App\Models\Floor\Floor;
use App\Models\Mapping\MappingVersion;
use App\Models\Npc\Npc;
use App\Models\Npc\NpcType;
use App\Models\Path;
use App\Models\Polyline;
use App\Service\CombatLog\Logging\CombatLogMappingVersionServiceLoggingInterface;
use App\Service\Coordinates\CoordinatesService;
use App\Service\Coordinates\CoordinatesServiceInterface;
use Exception;
use Illuminate\Support\Carbon;
Expand Down Expand Up @@ -67,7 +72,7 @@ public function createMappingVersionFromChallengeMode(string $filePath): ?Mappin
return $mappingVersion;
}

public function createMappingVersionFromDungeonOrRaid(string $filePath, ?MappingVersion $mappingVersion = null): ?MappingVersion
public function createMappingVersionFromDungeonOrRaid(string $filePath, ?MappingVersion $mappingVersion = null, bool $enemyConnections = false): ?MappingVersion
{
$this->log->createMappingVersionFromDungeonOrRaidStart($filePath);
try {
Expand All @@ -79,7 +84,7 @@ public function createMappingVersionFromDungeonOrRaid(string $filePath, ?Mapping
}

return $dungeon;
}, $mappingVersion);
}, $mappingVersion, $enemyConnections);
} finally {
$this->log->createMappingVersionFromDungeonOrRaidEnd();
}
Expand All @@ -90,7 +95,8 @@ public function createMappingVersionFromDungeonOrRaid(string $filePath, ?Mapping
private function createMappingVersionFromCombatLog(
string $filePath,
callable $extractDungeonCallable,
?MappingVersion $mappingVersion = null
?MappingVersion $mappingVersion = null,
bool $enemyConnections = false
): ?MappingVersion {
$targetFilePath = $this->combatLogService->extractCombatLog($filePath) ?? $filePath;

Expand All @@ -113,7 +119,16 @@ private function createMappingVersionFromCombatLog(
/** @var Collection<Npc> $npcs */
$npcs = collect();

$this->combatLogService->parseCombatLog($targetFilePath, function (int $combatLogVersion, bool $advancedLoggingEnabled, string $rawEvent, int $lineNr) use ($extractDungeonCallable, $hasExistingMappingVersion, &$mappingVersion, &$dungeon, &$currentFloor, &$npcs) {
$enemiesAttributes = [];
$enemyConnectionsAttributes = [];
/** @var LatLng|null $previousEnemyLatLng */
$previousEnemyLatLng = null;

$this->combatLogService->parseCombatLog($targetFilePath, function (int $combatLogVersion, bool $advancedLoggingEnabled, string $rawEvent, int $lineNr)
use (
$extractDungeonCallable, $hasExistingMappingVersion, &$mappingVersion, &$dungeon, &$currentFloor, &$npcs,
&$enemiesAttributes, &$enemyConnectionsAttributes, &$previousEnemyLatLng
) {
$this->log->addContext('lineNr', ['combatLogVersion' => $combatLogVersion, 'rawEvent' => trim($rawEvent), 'lineNr' => $lineNr]);

$combatLogEntry = (new CombatLogEntry($rawEvent));
Expand Down Expand Up @@ -212,13 +227,28 @@ private function createMappingVersionFromCombatLog(
)
);

Enemy::create(array_merge([
$enemiesAttributes[] = array_merge([
'floor_id' => $currentFloor->id,
'mapping_version_id' => $mappingVersion->id,
'npc_id' => $guid->getId(),
'required' => 0,
'skippable' => 0,
], $latLng->toArray()));
], $latLng->toArray());

$enemyConnectionsAttributes[] = [
'mapping_version_id' => $mappingVersion->id,
'floor_id' => $currentFloor->id,
'polyline' => [
'model_id' => -1,
'model_class' => EnemyPatrol::class,
'lat_lngs' => [
['lat' => $previousEnemyLatLng?->getLat() ?? CoordinatesService::MAP_MAX_LAT, 'lng' => $previousEnemyLatLng?->getLng() ?? CoordinatesService::MAP_MAX_LNG],
['lat' => $latLng->getLat(), 'lng' => $latLng->getLng()],
],
],
];

$previousEnemyLatLng = $latLng;

$this->log->createMappingVersionFromCombatLogNewEnemy($currentFloor->id, $guid->getId());
}
Expand All @@ -227,6 +257,45 @@ private function createMappingVersionFromCombatLog(
return $parsedEvent;
});

Enemy::insert($enemiesAttributes);
if ($enemyConnections) {
$enemyConnectionsGradient = [
[0, '#00FF00'],
[50, '#0000BB'],
[100, '#FF0000'],
];

$weightStep = 100 / count($enemiesAttributes);

// Save all polylines
$currentWeight = 0;
$polyLines = [];
foreach ($enemyConnectionsAttributes as $enemyConnectionAttributes) {
$polyLineAttributes = array_merge($enemyConnectionAttributes['polyline'], [
'color' => pickHexFromHandlers($enemyConnectionsGradient, $currentWeight += $weightStep),
'vertices_json' => json_encode($enemyConnectionAttributes['polyline']['lat_lngs']),
]);

unset($polyLineAttributes['lat_lngs']);
$polyLines[] = Polyline::create($polyLineAttributes);
}

// Save all paths (as enemy patrols, so I can see them in the mapping version admin) and couple the polylines to them
$i = 0;
foreach ($enemyConnectionsAttributes as $enemyConnectionsAttribute) {
$polyline = $polyLines[$i];
$enemyConnectionsAttribute['polyline_id'] = $polyline->id;

$enemyPatrol = EnemyPatrol::create($enemyConnectionsAttribute);

$polyline->update([
'model_id' => $enemyPatrol->id,
]);

$i++;
}
}

// Remove the lineNr context since we stopped parsing lines, don't let the last line linger in the context
$this->log->removeContext('lineNr');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ interface CombatLogMappingVersionServiceInterface
{
public function createMappingVersionFromChallengeMode(string $filePath): ?MappingVersion;

public function createMappingVersionFromDungeonOrRaid(string $filePath, ?MappingVersion $mappingVersion = null): ?MappingVersion;
public function createMappingVersionFromDungeonOrRaid(string $filePath, ?MappingVersion $mappingVersion = null, bool $enemyConnections = false): ?MappingVersion;
}

0 comments on commit 8964e57

Please sign in to comment.