6352e8e319
all at once
228 lines
7.3 KiB
C++
228 lines
7.3 KiB
C++
#include "StarWarping.hpp"
|
|
#include "StarDataStreamExtra.hpp"
|
|
#include "StarLexicalCast.hpp"
|
|
#include "StarJsonExtra.hpp"
|
|
|
|
namespace Star {
|
|
|
|
EnumMap<WarpMode> WarpModeNames {
|
|
{WarpMode::None, "None"},
|
|
{WarpMode::BeamOnly, "BeamOnly"},
|
|
{WarpMode::DeployOnly, "DeployOnly"},
|
|
{WarpMode::BeamOrDeploy, "BeamOrDeploy"}
|
|
};
|
|
|
|
InstanceWorldId::InstanceWorldId() {}
|
|
|
|
InstanceWorldId::InstanceWorldId(String instance, Maybe<Uuid> uuid, Maybe<float> level)
|
|
: instance(move(instance)), uuid(move(uuid)), level(move(level)) {}
|
|
|
|
bool InstanceWorldId::operator==(InstanceWorldId const& rhs) const {
|
|
return tie(instance, uuid, level) == tie(rhs.instance, rhs.uuid, rhs.level);
|
|
}
|
|
|
|
bool InstanceWorldId::operator<(InstanceWorldId const& rhs) const {
|
|
return tie(instance, uuid, rhs.level) < tie(rhs.instance, rhs.uuid, rhs.level);
|
|
}
|
|
|
|
size_t hash<InstanceWorldId>::operator()(InstanceWorldId const& id) const {
|
|
return hashOf(id.instance, id.uuid, id.level);
|
|
}
|
|
|
|
DataStream& operator>>(DataStream& ds, InstanceWorldId& instanceWorldId) {
|
|
ds >> instanceWorldId.instance;
|
|
ds >> instanceWorldId.uuid;
|
|
ds >> instanceWorldId.level;
|
|
return ds;
|
|
}
|
|
|
|
DataStream& operator<<(DataStream& ds, InstanceWorldId const& instanceWorldId) {
|
|
ds << instanceWorldId.instance;
|
|
ds << instanceWorldId.uuid;
|
|
ds << instanceWorldId.level;
|
|
return ds;
|
|
}
|
|
|
|
String printWorldId(WorldId const& worldId) {
|
|
if (auto instanceWorldId = worldId.ptr<InstanceWorldId>()) {
|
|
if (instanceWorldId->level && *instanceWorldId->level < 0.0f)
|
|
throw StarException::format("InstanceWorldId level component cannot be negative");
|
|
|
|
String uuidPart = instanceWorldId->uuid ? instanceWorldId->uuid->hex() : "-";
|
|
String levelPart = instanceWorldId->level ? toString(*instanceWorldId->level) : "-";
|
|
return strf("InstanceWorld:%s:%s:%s", instanceWorldId->instance, uuidPart, levelPart);
|
|
} else if (auto celestialWorldId = worldId.ptr<CelestialWorldId>()) {
|
|
return strf("CelestialWorld:%s", *celestialWorldId);
|
|
} else if (auto clientShipWorldId = worldId.ptr<ClientShipWorldId>()) {
|
|
return strf("ClientShipWorld:%s", clientShipWorldId->hex());
|
|
} else {
|
|
return "Nowhere";
|
|
}
|
|
}
|
|
|
|
WorldId parseWorldId(String const& printedId) {
|
|
if (printedId.empty())
|
|
return WorldId();
|
|
|
|
auto parts = printedId.split(':', 1);
|
|
String const& type = parts.at(0);
|
|
|
|
if (type.equalsIgnoreCase("InstanceWorld")) {
|
|
auto rest = parts.at(1).split(":", 2);
|
|
if (rest.size() == 0 || rest.size() > 3)
|
|
throw StarException::format("Wrong number of parts in InstanceWorldId");
|
|
auto getOptPart = [](String part) -> Maybe<String> {
|
|
if (part.empty() || part == "-")
|
|
return {};
|
|
return part;
|
|
};
|
|
|
|
InstanceWorldId instanceWorldId{rest.at(0)};
|
|
if (rest.size() > 1) {
|
|
if (auto uuid = getOptPart(rest.at(1)))
|
|
instanceWorldId.uuid = Uuid(*uuid);
|
|
if (rest.size() > 2) {
|
|
if (auto level = getOptPart(rest.at(2))) {
|
|
instanceWorldId.level = lexicalCast<float>(*level);
|
|
if (*instanceWorldId.level < 0)
|
|
throw StarException::format("InstanceWorldId level component cannot be negative");
|
|
}
|
|
}
|
|
}
|
|
|
|
return instanceWorldId;
|
|
} else if (type.equalsIgnoreCase("CelestialWorld")) {
|
|
return CelestialWorldId(CelestialCoordinate(parts.at(1)));
|
|
} else if (type.equalsIgnoreCase("ClientShipWorld")) {
|
|
return ClientShipWorldId(Uuid(parts.at(1)));
|
|
} else if (type.equalsIgnoreCase("Nowhere")) {
|
|
return {};
|
|
} else {
|
|
throw StarException::format("Improper WorldId type '%s'", type);
|
|
}
|
|
}
|
|
|
|
std::ostream& operator<<(std::ostream& os, WorldId const& worldId) {
|
|
os << printWorldId(worldId);
|
|
return os;
|
|
}
|
|
|
|
Json spawnTargetToJson(SpawnTarget spawnTarget) {
|
|
if (spawnTarget.is<SpawnTargetUniqueEntity>())
|
|
return spawnTarget.get<SpawnTargetUniqueEntity>();
|
|
else if (spawnTarget.is<SpawnTargetPosition>())
|
|
return jsonFromVec2F(spawnTarget.get<SpawnTargetPosition>());
|
|
else if (spawnTarget.is<SpawnTargetX>())
|
|
return Json(spawnTarget.get<SpawnTargetX>());
|
|
else
|
|
return Json();
|
|
}
|
|
|
|
SpawnTarget spawnTargetFromJson(Json v) {
|
|
if (v.isNull())
|
|
return {};
|
|
else if (v.isType(Json::Type::String))
|
|
return SpawnTargetUniqueEntity(v.toString());
|
|
else if (v.isType(Json::Type::Float))
|
|
return SpawnTargetX(v.toFloat());
|
|
else
|
|
return SpawnTargetPosition(jsonToVec2F(v));
|
|
}
|
|
|
|
String printSpawnTarget(SpawnTarget spawnTarget) {
|
|
if (auto str = spawnTarget.ptr<SpawnTargetUniqueEntity>())
|
|
return *str;
|
|
else if (auto pos = spawnTarget.ptr<SpawnTargetPosition>())
|
|
return strf("%s.%s", (*pos)[0], (*pos)[1]);
|
|
else if (auto x = spawnTarget.ptr<SpawnTargetX>())
|
|
return toString(*x);
|
|
else
|
|
return "";
|
|
}
|
|
|
|
WarpToWorld::WarpToWorld() {}
|
|
|
|
WarpToWorld::WarpToWorld(WorldId world, SpawnTarget target) : world(move(world)), target(move(target)) {}
|
|
|
|
WarpToWorld::WarpToWorld(Json v) {
|
|
if (v) {
|
|
world = parseWorldId(v.getString("world"));
|
|
target = spawnTargetFromJson(v.get("target"));
|
|
}
|
|
}
|
|
|
|
bool WarpToWorld::operator==(WarpToWorld const& rhs) const {
|
|
return tie(world, target) == tie(rhs.world, rhs.target);
|
|
}
|
|
|
|
WarpToWorld::operator bool() const {
|
|
return (bool)world;
|
|
}
|
|
|
|
Json WarpToWorld::toJson() const {
|
|
return JsonObject{{"world", printWorldId(world)}, {"target", spawnTargetToJson(target)}};
|
|
}
|
|
|
|
WarpAction parseWarpAction(String const& warpString) {
|
|
if (warpString.equalsIgnoreCase("Return")) {
|
|
return WarpAlias::Return;
|
|
} else if (warpString.equalsIgnoreCase("OrbitedWorld")) {
|
|
return WarpAlias::OrbitedWorld;
|
|
} else if (warpString.equalsIgnoreCase("OwnShip")) {
|
|
return WarpAlias::OwnShip;
|
|
} else if (warpString.beginsWith("Player:", String::CaseSensitivity::CaseInsensitive)) {
|
|
auto parts = warpString.split(':', 1);
|
|
return WarpToPlayer(Uuid(parts.at(1)));
|
|
} else {
|
|
auto parts = warpString.split('=', 1);
|
|
auto world = parseWorldId(parts.at(0));
|
|
SpawnTarget target;
|
|
if (parts.size() == 2) {
|
|
auto const& targetPart = parts.at(1);
|
|
if (targetPart.regexMatch("\\d+.\\d+")) {
|
|
auto pos = targetPart.split(".", 1);
|
|
target = SpawnTargetPosition(Vec2F(lexicalCast<int>(pos.at(0)), lexicalCast<int>(pos.at(1))));
|
|
} else if (targetPart.regexMatch("\\d+")) {
|
|
target = SpawnTargetX(lexicalCast<int>(targetPart));
|
|
} else {
|
|
target = SpawnTargetUniqueEntity(targetPart);
|
|
}
|
|
}
|
|
return WarpToWorld(world, target);
|
|
}
|
|
}
|
|
|
|
String printWarpAction(WarpAction const& warpAction) {
|
|
if (auto warpAlias = warpAction.ptr<WarpAlias>()) {
|
|
if (*warpAlias == WarpAlias::Return)
|
|
return "Return";
|
|
else if (*warpAlias == WarpAlias::OrbitedWorld)
|
|
return "OrbitedWorld";
|
|
else if (*warpAlias == WarpAlias::OwnShip)
|
|
return "OwnShip";
|
|
} else if (auto warpToPlayer = warpAction.ptr<WarpToPlayer>()) {
|
|
return strf("Player:%s", warpToPlayer->hex());
|
|
} else if (auto warpToWorld = warpAction.ptr<WarpToWorld>()) {
|
|
auto toWorldString = printWorldId(warpToWorld->world);
|
|
if (auto spawnTarget = warpToWorld->target)
|
|
toWorldString = strf("%s=%s", toWorldString, printSpawnTarget(spawnTarget));
|
|
return toWorldString;
|
|
}
|
|
|
|
return "UnknownWarpAction";
|
|
}
|
|
|
|
DataStream& operator>>(DataStream& ds, WarpToWorld& warpToWorld) {
|
|
ds >> warpToWorld.world;
|
|
ds >> warpToWorld.target;
|
|
return ds;
|
|
}
|
|
|
|
DataStream& operator<<(DataStream& ds, WarpToWorld const& warpToWorld) {
|
|
ds << warpToWorld.world;
|
|
ds << warpToWorld.target;
|
|
return ds;
|
|
}
|
|
|
|
}
|