Remove broad command

This commit is contained in:
Vladislav Khorev committed 2026-11-06 21:30:17 +06:00
1 parent 1ab9f300b6
commit 3f68a8ba07
11 files changed
+120 -160

No files matched your search

+3 -1
View File
@@ -140,7 +140,9 @@ Snapshots have a monotonically increasing revision. `InternalGameServer` caches
- Script globals. - Script globals.
- Character transforms, attack targets, navigation destinations, stopping, - Character transforms, attack targets, navigation destinations, stopping,
facing, replanning, health, damage, death reset, attack combos, and animation facing, replanning, health, damage, death reset, attack combos, and animation
metadata. metadata. Character position, facing angle, home position, face target, and
enabled state use separate semantic commands; no whole-character commit
command is exposed.
- Interactive-object activation. - Interactive-object activation.
- Trigger-zone state. - Trigger-zone state.
- Quest-definition reloads. - Quest-definition reloads.
-18
View File
@@ -144,24 +144,6 @@ CharacterUpdateEvents CharacterState::update(
CharacterUpdateEvents events; CharacterUpdateEvents events;
if (!enabled) return events; if (!enabled) return events;
if (slowMoTimeRemaining > 0.0f) {
slowMoTimeRemaining = (std::max)(
0.0f, slowMoTimeRemaining - static_cast<float>(deltaMs) / 1000.0f);
float transitionProgress = 1.0f;
if (slowMoTimeRemaining > slowMoActiveTime - slowMoTransitionTime) {
const float timeInTransition = slowMoActiveTime - slowMoTimeRemaining;
transitionProgress = (std::min)(1.0f, timeInTransition / slowMoTransitionTime);
} else if (slowMoTimeRemaining < slowMoTransitionTime) {
transitionProgress = (std::max)(0.0f, slowMoTimeRemaining / slowMoTransitionTime);
}
const float speedMultiplier = isPlayer
? 1.0f + 0.5f * transitionProgress
: 1.0f - 0.9f * transitionProgress;
deltaMs = static_cast<std::int64_t>(
static_cast<float>(deltaMs) * speedMultiplier);
}
const CharacterObservation* attackTarget = context.attackTarget; const CharacterObservation* attackTarget = context.attackTarget;
const CharacterObservation* faceTarget = context.faceTarget; const CharacterObservation* faceTarget = context.faceTarget;
if (!attackTarget) { if (!attackTarget) {
-5
View File
@@ -97,11 +97,6 @@ public:
Eigen::Vector3f homePosition = Eigen::Vector3f::Zero(); Eigen::Vector3f homePosition = Eigen::Vector3f::Zero();
float maxHomeDrift = 3.0f; float maxHomeDrift = 3.0f;
// --- Slow-motion effect ---
float slowMoTimeRemaining = 0.0f;
float slowMoActiveTime = 6.0f;
float slowMoTransitionTime = 0.5f;
// --- Authoritative logical animation clock --- // --- Authoritative logical animation clock ---
// Frame counts are immutable metadata copied from loaded clips during // Frame counts are immutable metadata copied from loaded clips during
// character construction. Simulation advances animationFrame itself. // character construction. Simulation advances animationFrame itself.
+4 -25
View File
@@ -649,11 +649,10 @@ namespace FRG
Location* loc = currentLocation(); Location* loc = currentLocation();
if (!loc) return; if (!loc) return;
if (loc->player) { if (loc->player) {
loc->updateCharacterState(*loc->player, [&](CharacterState& workingState) { server().submit(SetCharacterPositionCommand{
workingState.position = destPos; destName, loc->player->entityId(), destPos});
workingState.facingAngle = destRotY; server().submit(SetCharacterFacingAngleCommand{
workingState.targetFacingAngle = destRotY; destName, loc->player->entityId(), destRotY, true});
});
loc->stopCharacter(*loc->player); loc->stopCharacter(*loc->player);
} }
loc->localState().cameraAzimuth = destRotY; loc->localState().cameraAzimuth = destRotY;
@@ -1536,26 +1535,6 @@ namespace FRG
return n; return n;
} }
void Game::activateSlowMoEffect() {
if (!currentLocation()) return;
if (currentLocation()->player) {
currentLocation()->updateCharacterState(
*currentLocation()->player, [](CharacterState& workingState) {
workingState.slowMoTimeRemaining = workingState.slowMoActiveTime;
});
}
for (auto& npc : currentLocation()->npcs) {
if (npc) {
currentLocation()->updateCharacterState(
*npc, [](CharacterState& workingState) {
workingState.slowMoTimeRemaining = workingState.slowMoActiveTime;
});
}
}
}
void Game::enterCameraDragMode(int eventX, int eventY) void Game::enterCameraDragMode(int eventX, int eventY)
{ {
cameraDragging = true; cameraDragging = true;
-2
View File
@@ -106,8 +106,6 @@ namespace FRG {
MenuManager menuManager; MenuManager menuManager;
void activateSlowMoEffect();
#ifdef EMSCRIPTEN #ifdef EMSCRIPTEN
static Game* s_instance; static Game* s_instance;
#endif #endif
+17 -42
View File
@@ -132,18 +132,6 @@ namespace FRG
locationId_, character.entityId(), target, std::move(callbackName)}); locationId_, character.entityId(), target, std::move(callbackName)});
} }
void Location::updateCharacterState(
Character& character,
const std::function<void(CharacterState&)>& mutation)
{
auto snapshot = character.stateSnapshot();
if (!snapshot) return;
CharacterState stateCopy = *snapshot;
mutation(stateCopy);
gameServer_.submit(CommitCharacterStateCommand{
locationId_, character.entityId(), std::move(stateCopy)});
}
void Location::clearCharacterAttackTarget(Character& character) void Location::clearCharacterAttackTarget(Character& character)
{ {
gameServer_.submit(ClearCharacterAttackTargetCommand{ gameServer_.submit(ClearCharacterAttackTargetCommand{
@@ -1847,7 +1835,6 @@ namespace FRG
void Location::update(int64_t delta, const LocationSimulationEvents& events) void Location::update(int64_t delta, const LocationSimulationEvents& events)
{ {
pathVisualization.update(delta);
synchronizeRemotePlayers(); synchronizeRemotePlayers();
auto locationState = stateSnapshot(); auto locationState = stateSnapshot();
if (!locationState) return; if (!locationState) return;
@@ -2022,7 +2009,7 @@ namespace FRG
Eigen::Vector3f camRight(cosAzim, 0.f, sinAzim); Eigen::Vector3f camRight(cosAzim, 0.f, sinAzim);
Eigen::Vector3f camForward(sinAzim * cosIncl, -sinIncl, -cosAzim * cosIncl); Eigen::Vector3f camForward(sinAzim * cosIncl, -sinIncl, -cosAzim * cosIncl);
Eigen::Vector3f camUp(sinAzim * sinIncl, cosIncl, -cosAzim * sinIncl); Eigen::Vector3f camUp(sinAzim * sinIncl, cosIncl, -cosAzim * sinIncl);
const Eigen::Vector3f playerPos = playerState->position; const Eigen::Vector3f playerPos = player->renderPosition();
Eigen::Vector3f camPos = playerPos + Eigen::Vector3f(-sinAzim * cosIncl, sinIncl, cosAzim * cosIncl) * Environment::zoom + Eigen::Vector3f(0,1,0); Eigen::Vector3f camPos = playerPos + Eigen::Vector3f(-sinAzim * cosIncl, sinIncl, cosAzim * cosIncl) * Environment::zoom + Eigen::Vector3f(0,1,0);
Eigen::Vector3f rayDir = (camForward + camRight * (ndcX * aspect * tanHalfFov) + camUp * (ndcY * tanHalfFov)).normalized(); Eigen::Vector3f rayDir = (camForward + camRight * (ndcX * aspect * tanHalfFov) + camUp * (ndcY * tanHalfFov)).normalized();
@@ -2065,10 +2052,7 @@ namespace FRG
? clickedObject->state.interactionPosition ? clickedObject->state.interactionPosition
: clickedObject->state.position; : clickedObject->state.position;
setCharacterTarget(*player, interactionTarget); setCharacterTarget(*player, interactionTarget);
auto updatedPlayerState = player->stateSnapshot(); pathVisualization.start(*player, interactionTarget);
if (updatedPlayerState && !updatedPlayerState->pathWaypoints.empty()) {
pathVisualization.start(*player, interactionTarget);
}
clearCharacterAttackTarget(*player); clearCharacterAttackTarget(*player);
//logger() << "[CLICK] Player moving to object..." << std::endl; //logger() << "[CLICK] Player moving to object..." << std::endl;
} }
@@ -2101,21 +2085,17 @@ namespace FRG
tryCharacterAttackCombo(*player); tryCharacterAttackCombo(*player);
} }
const std::string targetId = clickedNpc->entityId(); const std::string targetId = clickedNpc->entityId();
updateCharacterState(*player, [targetId](CharacterState& workingState) { gameServer_.submit(SetCharacterTargetCommand{
workingState.attackTargetId = targetId; locationId_, player->entityId(), targetId});
});
gameServer_.submit(SetLocationTargetsCommand{ gameServer_.submit(SetLocationTargetsCommand{
locationId_, std::string(), std::string(), std::string()}); locationId_, std::string(), std::string(), std::string()});
if (distance >= Character::kAttackRange) { if (distance >= Character::kAttackRange) {
setCharacterTarget(*player, clickedNpcState->position); setCharacterTarget(*player, clickedNpcState->position);
auto updatedPlayerState = player->stateSnapshot(); pathVisualization.start(
if (updatedPlayerState && !updatedPlayerState->pathWaypoints.empty()) { *player,
pathVisualization.start( clickedNpcState->position,
*player, PathVisualization::Style::Hostile);
clickedNpcState->position,
PathVisualization::Style::Hostile);
}
} }
if (distance <= clickedNpcState->interactionRadius) { if (distance <= clickedNpcState->interactionRadius) {
@@ -2131,9 +2111,9 @@ namespace FRG
// Already in talk range — fire immediately, stop, and face the player. // Already in talk range — fire immediately, stop, and face the player.
//logger() << "[CLICK] *** SUCCESS: Clicked on NPC index: " << npcIndex << " (in range) ***" << std::endl; //logger() << "[CLICK] *** SUCCESS: Clicked on NPC index: " << npcIndex << " (in range) ***" << std::endl;
setCharacterTarget(*player, playerState->position); setCharacterTarget(*player, playerState->position);
updateCharacterState(*npcs[npcIndex], [this](CharacterState& workingState) { gameServer_.submit(SetCharacterFaceTargetCommand{
workingState.faceTargetId = gameServer_.localPlayerId(); locationId_, npcs[npcIndex]->entityId(),
}); gameServer_.localPlayerId()});
scriptEngine.callNpcInteractCallback(clickedNpc->entityId()); scriptEngine.callNpcInteractCallback(clickedNpc->entityId());
gameServer_.submit(SetLocationTargetsCommand{ gameServer_.submit(SetLocationTargetsCommand{
locationId_, std::string(), std::string(), std::string()}); locationId_, std::string(), std::string(), std::string()});
@@ -2142,10 +2122,7 @@ namespace FRG
//logger() << "[CLICK] NPC " << npcIndex << " out of talk range (distance " << distance //logger() << "[CLICK] NPC " << npcIndex << " out of talk range (distance " << distance
// << " > " << NPC_TALK_DISTANCE << "); walking to NPC..." << std::endl; // << " > " << NPC_TALK_DISTANCE << "); walking to NPC..." << std::endl;
setCharacterTarget(*player, clickedNpcState->position); setCharacterTarget(*player, clickedNpcState->position);
auto updatedPlayerState = player->stateSnapshot(); pathVisualization.start(*player, clickedNpcState->position);
if (updatedPlayerState && !updatedPlayerState->pathWaypoints.empty()) {
pathVisualization.start(*player, clickedNpcState->position);
}
gameServer_.submit(SetLocationTargetsCommand{ gameServer_.submit(SetLocationTargetsCommand{
locationId_, std::string(), clickedNpc->entityId(), locationId_, std::string(), clickedNpc->entityId(),
std::string()}); std::string()});
@@ -2173,13 +2150,10 @@ namespace FRG
locationId_, std::string(), std::string(), locationId_, std::string(), std::string(),
clickedTeleport->id}); clickedTeleport->id});
setCharacterTarget(*player, clickedTeleport->position); setCharacterTarget(*player, clickedTeleport->position);
auto updatedPlayerState = player->stateSnapshot(); pathVisualization.start(
if (updatedPlayerState && !updatedPlayerState->pathWaypoints.empty()) { *player,
pathVisualization.start( clickedTeleport->position,
*player, PathVisualization::Style::Teleport);
clickedTeleport->position,
PathVisualization::Style::Teleport);
}
clearCharacterAttackTarget(*player); clearCharacterAttackTarget(*player);
} else { } else {
const Eigen::Vector3f clickedDestination(hit.x(), 0.f, hit.z()); const Eigen::Vector3f clickedDestination(hit.x(), 0.f, hit.z());
@@ -2235,6 +2209,7 @@ namespace FRG
void Location::updatePresentation(int64_t delta) void Location::updatePresentation(int64_t delta)
{ {
dialogueSystem.update(static_cast<int>(delta)); dialogueSystem.update(static_cast<int>(delta));
pathVisualization.update(delta);
for (auto& tz : teleportZones) for (auto& tz : teleportZones)
tz.update(static_cast<float>(delta)); tz.update(static_cast<float>(delta));
} }
+1 -3
View File
@@ -80,6 +80,7 @@ namespace FRG
// Detaches the (shared, longer-lived) player from this location. // Detaches the (shared, longer-lived) player from this location.
~Location(); ~Location();
const std::string& locationId() const { return locationId_; } const std::string& locationId() const { return locationId_; }
IGameServer& gameServer() { return gameServer_; }
std::shared_ptr<const LocationNetworkState> stateSnapshot() const; std::shared_ptr<const LocationNetworkState> stateSnapshot() const;
LocationLocalState& localState() { return *localState_; } LocationLocalState& localState() { return *localState_; }
const LocationLocalState& localState() const { return *localState_; } const LocationLocalState& localState() const { return *localState_; }
@@ -175,9 +176,6 @@ namespace FRG
bool switchNavigation(int index); bool switchNavigation(int index);
void setCharacterTarget(Character& character, const Eigen::Vector3f& target, void setCharacterTarget(Character& character, const Eigen::Vector3f& target,
std::string callbackName = ""); std::string callbackName = "");
void updateCharacterState(
Character& character,
const std::function<void(CharacterState&)>& mutation);
void clearCharacterAttackTarget(Character& character); void clearCharacterAttackTarget(Character& character);
void stopCharacter(Character& character); void stopCharacter(Character& character);
void faceCharacter(Character& character, std::string targetId); void faceCharacter(Character& character, std::string targetId);
+20 -44
View File
@@ -124,9 +124,8 @@ namespace FRG {
if (cbName.empty()) if (cbName.empty())
std::cerr << "[script] npc_walk_to: on_arrived must be a global Lua function\n"; std::cerr << "[script] npc_walk_to: on_arrived must be a global Lua function\n";
} }
loc->updateCharacterState(*npc, [x, z](CharacterState& workingState) { loc->gameServer().submit(SetCharacterHomePositionCommand{
workingState.homePosition = Eigen::Vector3f(x, 0.f, z); loc->locationId(), npc->entityId(), Eigen::Vector3f(x, 0.f, z)});
});
loc->setCharacterTarget( loc->setCharacterTarget(
*npc, Eigen::Vector3f(x, y, z), std::move(cbName)); *npc, Eigen::Vector3f(x, y, z), std::move(cbName));
}); });
@@ -142,18 +141,16 @@ namespace FRG {
const float rad = angle * static_cast<float>(M_PI) / 180.f; const float rad = angle * static_cast<float>(M_PI) / 180.f;
logger() << "[script] npc_rotate_to: " << npcId << " angle " << angle << " degrees (" << rad << " radians)" << std::endl; logger() << "[script] npc_rotate_to: " << npcId << " angle " << angle << " degrees (" << rad << " radians)" << std::endl;
loc->updateCharacterState(*npc, [rad](CharacterState& workingState) { loc->gameServer().submit(SetCharacterFacingAngleCommand{
workingState.targetFacingAngle = rad; loc->locationId(), npc->entityId(), rad, false});
});
}); });
api.set_function("player_rotate_to", api.set_function("player_rotate_to",
[loc](float angle) { [loc](float angle) {
const float rad = angle * static_cast<float>(M_PI) / 180.f; const float rad = angle * static_cast<float>(M_PI) / 180.f;
logger() << "[script] player_rotate_to: angle " << angle << " degrees (" << rad << " radians)" << std::endl; logger() << "[script] player_rotate_to: angle " << angle << " degrees (" << rad << " radians)" << std::endl;
loc->updateCharacterState(*loc->player, [rad](CharacterState& workingState) { loc->gameServer().submit(SetCharacterFacingAngleCommand{
workingState.targetFacingAngle = rad; loc->locationId(), loc->player->entityId(), rad, false});
});
}); });
api.set_function("player_stop_and_rotate_to_npc", api.set_function("player_stop_and_rotate_to_npc",
@@ -188,9 +185,9 @@ namespace FRG {
if (cbName.empty()) if (cbName.empty())
std::cerr << "[script] player_walk_to: on_arrived must be a global Lua function\n"; std::cerr << "[script] player_walk_to: on_arrived must be a global Lua function\n";
} }
loc->updateCharacterState(*loc->player, [x, z](CharacterState& workingState) { loc->gameServer().submit(SetCharacterHomePositionCommand{
workingState.homePosition = Eigen::Vector3f(x, 0.f, z); loc->locationId(), loc->player->entityId(),
}); Eigen::Vector3f(x, 0.f, z)});
loc->setCharacterTarget( loc->setCharacterTarget(
*loc->player, Eigen::Vector3f(x, y, z), std::move(cbName)); *loc->player, Eigen::Vector3f(x, y, z), std::move(cbName));
}); });
@@ -440,13 +437,7 @@ namespace FRG {
if (loc->player) if (loc->player)
{ {
loc->setCharacterHp(*loc->player, value); loc->setCharacterHp(*loc->player, value);
loc->updateCharacterState(*loc->player, [](CharacterState& workingState) { loc->resetCharacterAfterDeath(*loc->player);
if (workingState.currentState == AnimationState::ACTION_TO_DEATH ||
workingState.currentState == AnimationState::DEATH_IDLE) {
workingState.currentState = AnimationState::STAND;
workingState.resetAnim = true;
}
});
} }
}); });
// get_player_hp() → float (0 if no player) // get_player_hp() → float (0 if no player)
@@ -602,10 +593,8 @@ namespace FRG {
return; return;
} }
Eigen::Vector3f pos(x, y, z); Eigen::Vector3f pos(x, y, z);
loc->updateCharacterState(*npc, [&pos](CharacterState& workingState) { loc->gameServer().submit(SetCharacterPositionCommand{
workingState.position = pos; loc->locationId(), npc->entityId(), pos, true});
workingState.homePosition = pos;
});
loc->setCharacterTarget(*npc, pos); loc->setCharacterTarget(*npc, pos);
}); });
@@ -618,10 +607,8 @@ namespace FRG {
return; return;
} }
const float rad = angle * static_cast<float>(M_PI) / 180.f; const float rad = angle * static_cast<float>(M_PI) / 180.f;
loc->updateCharacterState(*npc, [rad](CharacterState& workingState) { loc->gameServer().submit(SetCharacterFacingAngleCommand{
workingState.facingAngle = rad; loc->locationId(), npc->entityId(), rad, true});
workingState.targetFacingAngle = rad;
});
}); });
// set_npc_enabled(npc_id, enabled) // set_npc_enabled(npc_id, enabled)
@@ -632,34 +619,23 @@ namespace FRG {
std::cerr << "[script] set_npc_enabled: unknown NPC id '" << npcId << "'\n"; std::cerr << "[script] set_npc_enabled: unknown NPC id '" << npcId << "'\n";
return; return;
} }
loc->updateCharacterState(*npc, [value](CharacterState& workingState) { loc->gameServer().submit(SetCharacterEnabledCommand{
workingState.enabled = value; loc->locationId(), npc->entityId(), value});
workingState.attack = 0;
workingState.attack_cooldown = 0;
workingState.currentState = AnimationState::STAND;
if (workingState.canAttack)
workingState.attackTargetId = "player";
workingState.battle_state = 0;
});
}); });
api.set_function("player_set_position", api.set_function("player_set_position",
[loc](float x, float y, float z) { [loc](float x, float y, float z) {
Eigen::Vector3f pos(x, y, z); Eigen::Vector3f pos(x, y, z);
loc->updateCharacterState(*loc->player, [&pos](CharacterState& workingState) { loc->gameServer().submit(SetCharacterPositionCommand{
workingState.position = pos; loc->locationId(), loc->player->entityId(), pos, true});
workingState.homePosition = pos;
});
loc->setCharacterTarget(*loc->player, pos); loc->setCharacterTarget(*loc->player, pos);
}); });
api.set_function("player_set_rotation", api.set_function("player_set_rotation",
[loc](float angle) { [loc](float angle) {
const float rad = angle * static_cast<float>(M_PI) / 180.f; const float rad = angle * static_cast<float>(M_PI) / 180.f;
loc->updateCharacterState(*loc->player, [rad](CharacterState& workingState) { loc->gameServer().submit(SetCharacterFacingAngleCommand{
workingState.facingAngle = rad; loc->locationId(), loc->player->entityId(), rad, true});
workingState.targetFacingAngle = rad;
});
}); });
// move_object(name, x, y, z, duration_sec [, on_complete]) // move_object(name, x, y, z, duration_sec [, on_complete])
+28 -9
View File
@@ -136,17 +136,38 @@ struct SetQuestActiveObjectiveCommand {
}; };
struct SetGlobalIntCommand { std::string key; int value; }; struct SetGlobalIntCommand { std::string key; int value; };
struct SetGlobalFloatCommand { std::string key; float value; }; struct SetGlobalFloatCommand { std::string key; float value; };
struct SetCharacterTransformCommand { struct SetCharacterPositionCommand {
std::string locationId;
std::string characterId;
Eigen::Vector3f position;
bool updateHomePosition = false;
};
struct SetCharacterFacingAngleCommand {
std::string locationId;
std::string characterId;
float angle;
bool setCurrentAngle = false;
};
struct SetCharacterHomePositionCommand {
std::string locationId; std::string locationId;
std::string characterId; std::string characterId;
Eigen::Vector3f position; Eigen::Vector3f position;
float facingAngle;
}; };
struct SetCharacterTargetCommand { struct SetCharacterTargetCommand {
std::string locationId; std::string locationId;
std::string characterId; std::string characterId;
std::string targetId; std::string targetId;
}; };
struct SetCharacterFaceTargetCommand {
std::string locationId;
std::string characterId;
std::string targetId;
};
struct SetCharacterEnabledCommand {
std::string locationId;
std::string characterId;
bool enabled;
};
struct ClearCharacterAttackTargetCommand { struct ClearCharacterAttackTargetCommand {
std::string locationId; std::string locationId;
std::string characterId; std::string characterId;
@@ -196,11 +217,6 @@ struct DamageCharacterCommand {
float amount; float amount;
std::string attackerId; std::string attackerId;
}; };
struct CommitCharacterStateCommand {
std::string locationId;
std::string characterId;
CharacterState state;
};
struct SetInteractiveObjectActiveCommand { struct SetInteractiveObjectActiveCommand {
std::string locationId; std::string locationId;
std::string objectId; std::string objectId;
@@ -241,8 +257,12 @@ using GameCommand = std::variant<
SetQuestActiveObjectiveCommand, SetQuestActiveObjectiveCommand,
SetGlobalIntCommand, SetGlobalIntCommand,
SetGlobalFloatCommand, SetGlobalFloatCommand,
SetCharacterTransformCommand, SetCharacterPositionCommand,
SetCharacterFacingAngleCommand,
SetCharacterHomePositionCommand,
SetCharacterTargetCommand, SetCharacterTargetCommand,
SetCharacterFaceTargetCommand,
SetCharacterEnabledCommand,
ClearCharacterAttackTargetCommand, ClearCharacterAttackTargetCommand,
SetCharacterDestinationCommand, SetCharacterDestinationCommand,
StopCharacterCommand, StopCharacterCommand,
@@ -253,7 +273,6 @@ using GameCommand = std::variant<
SetCharacterHealthCommand, SetCharacterHealthCommand,
SetCharacterAnimationMetadataCommand, SetCharacterAnimationMetadataCommand,
DamageCharacterCommand, DamageCharacterCommand,
CommitCharacterStateCommand,
SetInteractiveObjectActiveCommand, SetInteractiveObjectActiveCommand,
SetTriggerZoneEnabledCommand, SetTriggerZoneEnabledCommand,
ReloadQuestDefinitionsCommand>; ReloadQuestDefinitionsCommand>;
+32 -7
View File
@@ -378,18 +378,47 @@ void InternalGameServer::submit(const GameCommand& command)
state_.globalInts[value.key] = value.value; state_.globalInts[value.key] = value.value;
} else if constexpr (std::is_same_v<T, SetGlobalFloatCommand>) { } else if constexpr (std::is_same_v<T, SetGlobalFloatCommand>) {
state_.globalFloats[value.key] = value.value; state_.globalFloats[value.key] = value.value;
} else if constexpr (std::is_same_v<T, SetCharacterTransformCommand>) { } else if constexpr (std::is_same_v<T, SetCharacterPositionCommand>) {
CharacterState* character = CharacterState* character =
state_.findCharacter(value.locationId, value.characterId); state_.findCharacter(value.locationId, value.characterId);
if (character) { if (character) {
character->position = value.position; character->position = value.position;
character->facingAngle = value.facingAngle; if (value.updateHomePosition)
character->targetFacingAngle = value.facingAngle; character->homePosition = value.position;
} }
} else if constexpr (std::is_same_v<T, SetCharacterFacingAngleCommand>) {
CharacterState* character =
state_.findCharacter(value.locationId, value.characterId);
if (character) {
character->targetFacingAngle = value.angle;
if (value.setCurrentAngle)
character->facingAngle = value.angle;
}
} else if constexpr (std::is_same_v<T, SetCharacterHomePositionCommand>) {
CharacterState* character =
state_.findCharacter(value.locationId, value.characterId);
if (character)
character->homePosition = value.position;
} else if constexpr (std::is_same_v<T, SetCharacterTargetCommand>) { } else if constexpr (std::is_same_v<T, SetCharacterTargetCommand>) {
CharacterState* character = CharacterState* character =
state_.findCharacter(value.locationId, value.characterId); state_.findCharacter(value.locationId, value.characterId);
if (character) character->attackTargetId = value.targetId; if (character) character->attackTargetId = value.targetId;
} else if constexpr (std::is_same_v<T, SetCharacterFaceTargetCommand>) {
CharacterState* character =
state_.findCharacter(value.locationId, value.characterId);
if (character) character->faceTargetId = value.targetId;
} else if constexpr (std::is_same_v<T, SetCharacterEnabledCommand>) {
CharacterState* character =
state_.findCharacter(value.locationId, value.characterId);
if (character) {
character->enabled = value.enabled;
character->attack = 0;
character->attack_cooldown = 0;
character->currentState = AnimationState::STAND;
if (character->canAttack)
character->attackTargetId = "player";
character->battle_state = 0;
}
} else if constexpr (std::is_same_v<T, ClearCharacterAttackTargetCommand>) { } else if constexpr (std::is_same_v<T, ClearCharacterAttackTargetCommand>) {
CharacterState* character = CharacterState* character =
state_.findCharacter(value.locationId, value.characterId); state_.findCharacter(value.locationId, value.characterId);
@@ -445,10 +474,6 @@ void InternalGameServer::submit(const GameCommand& command)
CharacterState* character = CharacterState* character =
state_.findCharacter(value.locationId, value.characterId); state_.findCharacter(value.locationId, value.characterId);
if (character) character->hp = (std::max)(0.f, character->hp - (std::max)(0.f, value.amount)); if (character) character->hp = (std::max)(0.f, character->hp - (std::max)(0.f, value.amount));
} else if constexpr (std::is_same_v<T, CommitCharacterStateCommand>) {
CharacterState* character =
state_.findCharacter(value.locationId, value.characterId);
if (character) *character = value.state;
} else if constexpr (std::is_same_v<T, SetInteractiveObjectActiveCommand>) { } else if constexpr (std::is_same_v<T, SetInteractiveObjectActiveCommand>) {
auto location = state_.locations.find(value.locationId); auto location = state_.locations.find(value.locationId);
if (location == state_.locations.end()) return; if (location == state_.locations.end()) return;
+15 -4
View File
@@ -104,17 +104,28 @@ namespace FRG {
if (!state) return; if (!state) return;
std::vector<Eigen::Vector3f> route; std::vector<Eigen::Vector3f> route;
route.reserve(state->pathWaypoints.size() + 1); route.reserve(state->pathWaypoints.size() + 1);
route.push_back(Eigen::Vector3f(state->position.x(), 0.0f, state->position.z())); const Eigen::Vector3f renderPosition = player.renderPosition();
route.push_back(Eigen::Vector3f(renderPosition.x(), 0.0f, renderPosition.z()));
const size_t firstWaypoint = (std::min)( const size_t firstWaypoint = (std::min)(
state->currentWaypointIndex, state->pathWaypoints.size()); state->currentWaypointIndex, state->pathWaypoints.size());
for (size_t i = firstWaypoint; i < state->pathWaypoints.size(); ++i) { for (size_t i = firstWaypoint; i < state->pathWaypoints.size(); ++i) {
const Eigen::Vector3f& waypoint = state->pathWaypoints[i]; const Eigen::Vector3f& waypoint = state->pathWaypoints[i];
route.push_back(Eigen::Vector3f(waypoint.x(), 0.0f, waypoint.z())); route.push_back(Eigen::Vector3f(waypoint.x(), 0.0f, waypoint.z()));
} }
const Eigen::Vector3f clickedPosition(
clickedDestination.x(), 0.0f, clickedDestination.z());
if (route.size() == 1 ||
(route.back() - clickedPosition).norm() > 0.5f) {
// A remote destination is not present in the replica yet, or the
// replica still contains the route for a previous click. Preview
// the new intent directly until authoritative waypoints catch up.
route.clear();
route.push_back(Eigen::Vector3f(
renderPosition.x(), 0.0f, renderPosition.z()));
route.push_back(clickedPosition);
}
destination = route.size() > 1 destination = clickedPosition;
? route.back()
: Eigen::Vector3f(clickedDestination.x(), 0.0f, clickedDestination.z());
float totalLength = 0.0f; float totalLength = 0.0f;
for (size_t i = 1; i < route.size(); ++i) { for (size_t i = 1; i < route.size(); ++i) {