#include "StarWarping.hpp" #include "StarDataStreamExtra.hpp" #include "StarLexicalCast.hpp" #include "StarJsonExtra.hpp" namespace Star { EnumMap WarpModeNames { {WarpMode::None, "None"}, {WarpMode::BeamOnly, "BeamOnly"}, {WarpMode::DeployOnly, "DeployOnly"}, {WarpMode::BeamOrDeploy, "BeamOrDeploy"} }; InstanceWorldId::InstanceWorldId() {} InstanceWorldId::InstanceWorldId(String instance, Maybe uuid, Maybe level) : instance(std::move(instance)), uuid(std::move(uuid)), level(std::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::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()) { 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:{}:{}:{}", instanceWorldId->instance, uuidPart, levelPart); } else if (auto celestialWorldId = worldId.ptr()) { return strf("CelestialWorld:{}", *celestialWorldId); } else if (auto clientShipWorldId = worldId.ptr()) { return strf("ClientShipWorld:{}", 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 { 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(*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 '{}'", type); } } std::ostream& operator<<(std::ostream& os, CelestialWorldId const& worldId) { os << (CelestialCoordinate)worldId; return os; } std::ostream& operator<<(std::ostream& os, ClientShipWorldId const& worldId) { os << ((Uuid)worldId).hex(); return os; } std::ostream& operator<<(std::ostream& os, InstanceWorldId const& worldId) { os << printWorldId(worldId); return os; } std::ostream& operator<<(std::ostream& os, WorldId const& worldId) { os << printWorldId(worldId); return os; } Json spawnTargetToJson(SpawnTarget spawnTarget) { if (spawnTarget.is()) return spawnTarget.get(); else if (spawnTarget.is()) return jsonFromVec2F(spawnTarget.get()); else if (spawnTarget.is()) return Json(spawnTarget.get()); 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()) return *str; else if (auto pos = spawnTarget.ptr()) return strf("{}.{}", (*pos)[0], (*pos)[1]); else if (auto x = spawnTarget.ptr()) return toString(x->t); else return ""; } WarpToWorld::WarpToWorld() {} WarpToWorld::WarpToWorld(WorldId world, SpawnTarget target) : world(std::move(world)), target(std::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(pos.at(0)), lexicalCast(pos.at(1)))); } else if (targetPart.regexMatch("\\d+")) { target = SpawnTargetX(lexicalCast(targetPart)); } else { target = SpawnTargetUniqueEntity(targetPart); } } return WarpToWorld(world, target); } } String printWarpAction(WarpAction const& warpAction) { if (auto warpAlias = warpAction.ptr()) { 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()) { return strf("Player:{}", warpToPlayer->hex()); } else if (auto warpToWorld = warpAction.ptr()) { auto toWorldString = printWorldId(warpToWorld->world); if (auto spawnTarget = warpToWorld->target) toWorldString = strf("{}={}", 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; } }