osb/source/game/StarStagehand.cpp
Kae 4b0bc220e4 Support for changing the game's timescale
Context-specific (like per-world) timescales can also be added later
2023-07-21 00:58:49 +10:00

196 lines
5.4 KiB
C++

#include "StarStagehand.hpp"
#include "StarDataStreamExtra.hpp"
#include "StarJsonExtra.hpp"
#include "StarConfigLuaBindings.hpp"
#include "StarEntityLuaBindings.hpp"
#include "StarBehaviorLuaBindings.hpp"
#include "StarLuaGameConverters.hpp"
namespace Star {
Stagehand::Stagehand(Json const& config)
: Stagehand() {
setUniqueId(config.optString("uniqueId"));
readConfig(config);
}
Stagehand::Stagehand(ByteArray const& netStore)
: Stagehand() {
readConfig(DataStreamBuffer::deserialize<Json>(netStore));
}
Json Stagehand::diskStore() const {
auto saveData = m_config.setAll({
{"position", jsonFromVec2F({m_xPosition.get(), m_yPosition.get()})},
{"uniqueId", jsonFromMaybe(uniqueId())}
});
if (!m_scripted)
return saveData;
else
return saveData.set("scriptStorage", m_scriptComponent.getScriptStorage());
}
ByteArray Stagehand::netStore() {
return DataStreamBuffer::serialize(m_config);
}
void Stagehand::init(World* world, EntityId entityId, EntityMode mode) {
Entity::init(world, entityId, mode);
if (isMaster() && m_scripted) {
m_scriptComponent.addCallbacks("stagehand", makeStagehandCallbacks());
m_scriptComponent.addCallbacks("config", LuaBindings::makeConfigCallbacks([this](String const& name, Json const& def) {
return m_config.query(name, def);
}));
m_scriptComponent.addCallbacks("entity", LuaBindings::makeEntityCallbacks(this));
m_scriptComponent.addCallbacks("behavior", LuaBindings::makeBehaviorLuaCallbacks(&m_behaviors));
m_scriptComponent.init(world);
}
}
void Stagehand::uninit() {
Entity::uninit();
if (m_scripted) {
m_scriptComponent.uninit();
m_scriptComponent.removeCallbacks("stagehand");
m_scriptComponent.removeCallbacks("config");
m_scriptComponent.removeCallbacks("entity");
}
}
EntityType Stagehand::entityType() const {
return EntityType::Stagehand;
}
void Stagehand::setPosition(Vec2F const& position) {
m_xPosition.set(position[0]);
m_yPosition.set(position[1]);
}
Vec2F Stagehand::position() const {
return {m_xPosition.get(), m_yPosition.get()};
}
RectF Stagehand::metaBoundBox() const {
return m_boundBox;
}
pair<ByteArray, uint64_t> Stagehand::writeNetState(uint64_t fromVersion) {
return m_netGroup.writeNetState(fromVersion);
}
void Stagehand::readNetState(ByteArray data, float) {
m_netGroup.readNetState(move(data));
}
void Stagehand::update(float dt, uint64_t) {
if (!inWorld())
return;
if (isMaster() && m_scripted)
m_scriptComponent.update(m_scriptComponent.updateDt(dt));
if (world()->isClient()) {
auto boundBox = metaBoundBox().translated(position());
SpatialLogger::logPoly("world", PolyF(boundBox), { 0, 255, 255, 255 });
SpatialLogger::logLine("world", boundBox.min(), boundBox.max(), {0, 255, 255, 255});
SpatialLogger::logLine("world", { boundBox.xMin(), boundBox.yMax() }, { boundBox.xMax(), boundBox.yMin() }, {0, 255, 255, 255});
}
}
bool Stagehand::shouldDestroy() const {
return m_dead;
}
Maybe<LuaValue> Stagehand::callScript(String const& func, LuaVariadic<LuaValue> const& args) {
return m_scriptComponent.invoke(func, args);
}
Maybe<LuaValue> Stagehand::evalScript(String const& code) {
return m_scriptComponent.eval(code);
}
Stagehand::Stagehand() {
setPersistent(true);
m_netGroup.addNetElement(&m_xPosition);
m_netGroup.addNetElement(&m_yPosition);
m_netGroup.addNetElement(&m_uniqueIdNetState);
m_netGroup.setNeedsLoadCallback([this](bool) {
setUniqueId(m_uniqueIdNetState.get());
});
m_netGroup.setNeedsStoreCallback([this]() {
m_uniqueIdNetState.set(uniqueId());
});
}
void Stagehand::readConfig(Json config) {
m_config = config;
m_scripted = m_config.contains("scripts");
if (m_config.contains("position")) {
auto pos = jsonToVec2F(m_config.get("position"));
m_xPosition.set(pos[0]);
m_yPosition.set(pos[1]);
}
Maybe<RectF> broadcastArea = jsonToMaybe<RectF>(config.opt("broadcastArea").value(Json()), jsonToRectF);
if (broadcastArea && (broadcastArea->size()[0] < 0.0 || broadcastArea->size()[1] < 0.0))
broadcastArea.reset();
m_boundBox = broadcastArea.value(RectF(-5.0, -5.0, 5.0, 5.0));
if (m_scripted) {
m_scriptComponent.setScripts(jsonToStringList(m_config.getArray("scripts", JsonArray())));
m_scriptComponent.setUpdateDelta(m_config.getInt("scriptDelta", 5));
if (m_config.contains("scriptStorage"))
m_scriptComponent.setScriptStorage(m_config.getObject("scriptStorage"));
}
setKeepAlive(config.getBool("keepAlive", false));
}
LuaCallbacks Stagehand::makeStagehandCallbacks() {
LuaCallbacks callbacks;
callbacks.registerCallback("id", [this]() {
return entityId();
});
callbacks.registerCallback("position", [this]() {
return position();
});
callbacks.registerCallback("setPosition", [this](Vec2F const& position) {
setPosition(position);
});
callbacks.registerCallback("die", [this]() {
m_dead = true;
});
callbacks.registerCallback("typeName", [this]() {
return typeName();
});
callbacks.registerCallback("setUniqueId", [this](Maybe<String> const& uniqueId) {
setUniqueId(uniqueId);
});
return callbacks;
}
String Stagehand::typeName() const {
return m_config.getString("type");
}
Maybe<Json> Stagehand::receiveMessage(ConnectionId sendingConnection, String const& message, JsonArray const& args) {
return m_scriptComponent.handleMessage(message, sendingConnection == world()->connection(), args);
}
}