Redesign of animation queue for unreal, add get_tangibles_near to drivenengine
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -5,40 +5,26 @@
|
|||||||
// An animation queue is a fifo queue of animation steps. New animations are
|
// An animation queue is a fifo queue of animation steps. New animations are
|
||||||
// pushed on the back, and old ones are popped from the front.
|
// pushed on the back, and old ones are popped from the front.
|
||||||
//
|
//
|
||||||
// An animation step has an "action" which is usually the name of an animation,
|
// An animation step is a set of key-value pairs, where each key is an
|
||||||
// or it's a special token like "walk" or "warp." Each animation step shows the
|
// identifier, and each value is either a number, a boolean, an XYZ coordinate,
|
||||||
// resulting AnimState that the player finds himself in after executing the
|
// or a string. A key-value pair can be either persistent or nonpersistent.
|
||||||
// action.
|
// So a typical animation step might be:
|
||||||
//
|
//
|
||||||
// The first step in an animation queue always has id=0 and action="". This step
|
// action=walk [nonpersistent]
|
||||||
// represents the initial state of the sprite before any animations or
|
// xyz=3,4,5 [persistent]
|
||||||
// movements.
|
// facing=320 [persistent]
|
||||||
|
// plane=earth [persistent]
|
||||||
//
|
//
|
||||||
// To add new items to the AnimQueue, use this process: first, call add(id,
|
// Persistent values are retained from one animation step to the next,
|
||||||
// action). This adds a new step to the queue. Then, call set_xyz, set_facing,
|
// nonpersistent values exist for one animation step only.
|
||||||
// set_plane, or an other setter. These setters are meant to only be used
|
|
||||||
// immediately after calling 'add' to populate the new step.
|
|
||||||
//
|
//
|
||||||
// VERSION NUMBERS
|
// Animation steps are stored encoded as strings, which is convenient for
|
||||||
|
// passing the data to unreal, but it means that the animation step has to be
|
||||||
|
// decoded whenever you want access to the key-value pairs.
|
||||||
//
|
//
|
||||||
// The version number field: if the version number in the synchronous model is
|
// Each animation step has a hash value. The hash value is generated
|
||||||
// equal to the version number in the master model, then the two animqueues are
|
// by mixing the hash value of the previous step with the hash value
|
||||||
// guaranteed to be equal. Here's how we achieve that invariant:
|
// of the encoded string of key-value pairs.
|
||||||
//
|
|
||||||
// * In the master model, the version number starts at 1 and is auto-incremented
|
|
||||||
// every time the animation queue is mutated.
|
|
||||||
//
|
|
||||||
// * In the synchronous model, the version number is set to zero every time the
|
|
||||||
// animation queue is mutated. Note that master version numbers are never
|
|
||||||
// zero. Applying a patch also sets the version number to zero.
|
|
||||||
//
|
|
||||||
// * Serializing and deserializing causes the version number to be saved and
|
|
||||||
// restored in both master and synchronous models.
|
|
||||||
//
|
|
||||||
// * The routine 'update_version' should be called after difference
|
|
||||||
// transmission. This copies the version number from the master to the
|
|
||||||
// synchronous model. This is guaranteed to be safe because we just finished
|
|
||||||
// difference transmission, therefore, the queues should match.
|
|
||||||
//
|
//
|
||||||
///////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@@ -50,6 +36,7 @@
|
|||||||
#include "wrap-deque.hpp"
|
#include "wrap-deque.hpp"
|
||||||
#include "wrap-unordered-map.hpp"
|
#include "wrap-unordered-map.hpp"
|
||||||
|
|
||||||
|
#include "luastack.hpp"
|
||||||
#include "streambuffer.hpp"
|
#include "streambuffer.hpp"
|
||||||
#include "debugcollector.hpp"
|
#include "debugcollector.hpp"
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
@@ -57,184 +44,226 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
|
||||||
class AnimStep : public eng::nevernew {
|
enum AnimValueType {
|
||||||
friend class AnimQueue;
|
T_STRING,
|
||||||
public:
|
T_NUMBER,
|
||||||
enum {
|
T_BOOLEAN,
|
||||||
HAS_FACING = 1,
|
T_XYZ,
|
||||||
HAS_X = 2,
|
T_UNINITIALIZED
|
||||||
HAS_Y = 4,
|
};
|
||||||
HAS_Z = 8,
|
|
||||||
HAS_XYZ = 14,
|
|
||||||
HAS_GRAPHIC = 16,
|
|
||||||
HAS_PLANE = 32,
|
|
||||||
HAS_EVERYTHING = 63,
|
|
||||||
};
|
|
||||||
|
|
||||||
AnimStep();
|
struct AnimValue {
|
||||||
~AnimStep();
|
AnimValue() : persistent(false), type(T_UNINITIALIZED) {}
|
||||||
|
|
||||||
int64_t id() const { return id_; }
|
bool persistent;
|
||||||
int bits() const { return bits_; }
|
AnimValueType type;
|
||||||
|
eng::string str;
|
||||||
|
util::DXYZ xyz;
|
||||||
|
|
||||||
const eng::string &action() const { return action_; }
|
// These set the type, str, and xyz fields in a consistent way.
|
||||||
double facing() const { return facing_; }
|
void set_boolean(bool b);
|
||||||
float x() const { return xyz_.x; }
|
void set_number(double n);
|
||||||
float y() const { return xyz_.y; }
|
void set_xyz(const util::DXYZ &xyz);
|
||||||
float z() const { return xyz_.z; }
|
void set_string(std::string_view s);
|
||||||
const util::XYZ &xyz() const { return xyz_; }
|
|
||||||
const eng::string &graphic() const { return graphic_; }
|
|
||||||
const eng::string &plane() const { return plane_; }
|
|
||||||
|
|
||||||
bool has_facing() const { return bits_ & HAS_FACING; }
|
// The get the type, str, and xyz fields in a consistent way.
|
||||||
bool has_x() const { return bits_ & HAS_X; }
|
bool get_boolean() const;
|
||||||
bool has_y() const { return bits_ & HAS_Y; }
|
double get_number() const;
|
||||||
bool has_z() const { return bits_ & HAS_Z; }
|
const util::DXYZ &get_xyz() const;
|
||||||
bool has_xyz() const { return (bits_ & HAS_XYZ) == HAS_XYZ; }
|
std::string_view get_string() const;
|
||||||
bool has_graphic() const { return bits_ & AnimStep::HAS_GRAPHIC; }
|
|
||||||
bool has_plane() const { return bits_ & AnimStep::HAS_PLANE; }
|
|
||||||
|
|
||||||
void set_action(const eng::string &action);
|
// Copy the value from another animvalue. Don't copy the persistent flag.
|
||||||
void set_facing(float f);
|
void copy_value(const AnimValue &other);
|
||||||
void set_x(float f);
|
|
||||||
void set_y(float f);
|
|
||||||
void set_z(float z);
|
|
||||||
void set_xyz(const util::XYZ &xyz);
|
|
||||||
void set_graphic(const eng::string &g);
|
|
||||||
void set_plane(const eng::string &p);
|
|
||||||
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
// ExactlyEqual compares all fields.
|
|
||||||
bool exactly_equal(const AnimStep &other) const;
|
|
||||||
|
|
||||||
// LogicallyEqual only compares fields whose HAS_XXX bits are set.
|
|
||||||
bool logically_equal(const AnimStep &other) const;
|
|
||||||
|
|
||||||
// StateEqual is true if the plane, graphic, facing, and xyz match.
|
|
||||||
bool state_equal(const AnimStep &other) const;
|
|
||||||
|
|
||||||
// read/write the step using a stream buffer.
|
|
||||||
//
|
|
||||||
void write_into(StreamBuffer *sb) const;
|
|
||||||
void read_from(StreamBuffer *sb);
|
|
||||||
|
|
||||||
// Create an AnimStep from a lua table.
|
|
||||||
//
|
|
||||||
// Lua stack must contain a table, which may contain:
|
|
||||||
// action: "action"
|
|
||||||
// facing: 0.0 - 360.0
|
|
||||||
// x: x-coordinate
|
|
||||||
// y: y-coordinate
|
|
||||||
// z: z-coordinate
|
|
||||||
// graphic: "graphic"
|
|
||||||
// plane: "plane"
|
|
||||||
//
|
|
||||||
// aqback: the animation queue back, from which relative
|
|
||||||
// moves are computed.
|
|
||||||
//
|
|
||||||
void configure(LuaKeywordParser &kp, const AnimStep &aqback);
|
|
||||||
|
|
||||||
// Make this step into a first-step of an anim queue.
|
|
||||||
void keep_state_only();
|
|
||||||
|
|
||||||
// For any values that are unchanged in this step,
|
|
||||||
// echo the values of the previous step.
|
|
||||||
void echo(const AnimStep &prev);
|
|
||||||
|
|
||||||
// Verify that this step echoes the previous step.
|
|
||||||
bool echoes(const AnimStep &prev) const;
|
|
||||||
|
|
||||||
// Convert to a string for debugging purposes.
|
|
||||||
eng::string debug_string() const;
|
|
||||||
|
|
||||||
// Convert a string to an animstep (for testing only).
|
|
||||||
bool from_string(const eng::string &s);
|
|
||||||
|
|
||||||
private:
|
|
||||||
int64_t id_;
|
|
||||||
int16_t bits_;
|
|
||||||
eng::string action_;
|
|
||||||
|
|
||||||
float facing_;
|
|
||||||
util::XYZ xyz_;
|
|
||||||
eng::string graphic_;
|
|
||||||
eng::string plane_;
|
|
||||||
|
|
||||||
void config_store_string(lua_State *L, int idx, eng::string *target, int16_t bits, const char *name);
|
|
||||||
void config_store_number(lua_State *L, int idx, float *target, float offset, int16_t bits, const char *name);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class AnimQueue : public eng::nevernew {
|
class AnimState
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
using Map = eng::map<eng::string, AnimValue>;
|
||||||
|
Map map_;
|
||||||
|
|
||||||
|
// Set the default value, internal
|
||||||
|
//
|
||||||
|
eng::string add_default(const eng::string &name, const AnimValue &v, const AnimState *other);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// World type determines whether versions increment or autozero
|
// Clear everything
|
||||||
AnimQueue(WorldType wt);
|
//
|
||||||
|
void clear() { map_.clear(); }
|
||||||
|
|
||||||
// Simple getters.
|
// Set the persistent flag on a single variable.
|
||||||
const AnimStep &nth(int n) const { return steps_[n]; }
|
// If the variable isn't present, add it.
|
||||||
size_t size() const { return steps_.size(); }
|
//
|
||||||
|
void set_persistent(const eng::string &name);
|
||||||
|
|
||||||
|
// Return if it contains a value for the specified name.
|
||||||
|
//
|
||||||
|
bool contains(const eng::string &name) { return map_.find(name) != map_.end(); }
|
||||||
|
|
||||||
|
// Get the value of a specific variable.
|
||||||
|
// If the variable isn't present, return a default value.
|
||||||
|
//
|
||||||
|
bool get_boolean(const eng::string &name);
|
||||||
|
double get_number(const eng::string &name);
|
||||||
|
util::DXYZ get_xyz(const eng::string &name);
|
||||||
|
std::string_view get_string(const eng::string &name);
|
||||||
|
|
||||||
|
// Set a single variable to a value of a specified type.
|
||||||
|
// If the variable isn't present, add it.
|
||||||
|
//
|
||||||
|
void set_boolean(const eng::string &name, bool v);
|
||||||
|
void set_number(const eng::string &name, double v);
|
||||||
|
void set_xyz(const eng::string &name, const util::DXYZ &value);
|
||||||
|
void set_string(const eng::string &name, std::string_view value);
|
||||||
|
|
||||||
|
// Print a debug string into the stringstream.
|
||||||
|
//
|
||||||
|
void print_debug_string(eng::ostringstream &oss);
|
||||||
|
|
||||||
|
// Return the debug string.
|
||||||
|
eng::string debug_string();
|
||||||
|
|
||||||
|
// Constructs an empty state.
|
||||||
|
//
|
||||||
|
AnimState() {}
|
||||||
|
|
||||||
|
// Convert to an encoded string.
|
||||||
|
//
|
||||||
|
eng::string encode() const;
|
||||||
|
|
||||||
|
// Decode an encoded string.
|
||||||
|
//
|
||||||
|
void decode(std::string_view enc);
|
||||||
|
|
||||||
|
// Decode an encoded string, discarding non-persistent data.
|
||||||
|
//
|
||||||
|
void decode_persistent(std::string_view enc);
|
||||||
|
|
||||||
|
// Add default values for all builtin persistent variables.
|
||||||
|
//
|
||||||
|
// For each builtin default (plane, xyz, facing, bp, model)
|
||||||
|
//
|
||||||
|
// - Will generate an error if a value is already present,
|
||||||
|
// but the present value is of the wrong type.
|
||||||
|
//
|
||||||
|
// - If 'other' is not nullptr, then we look in 'other' for a default
|
||||||
|
// value. If a valid value of the correct type is present, it is
|
||||||
|
// used as the default value.
|
||||||
|
//
|
||||||
|
// - If no default value can be found in 'other', then a hardwired
|
||||||
|
// default value is provided.
|
||||||
|
//
|
||||||
|
eng::string add_defaults(const AnimState *other);
|
||||||
|
|
||||||
|
// Apply a configuration from a lua table.
|
||||||
|
//
|
||||||
|
// If a key already exists in the state, then type type from the table
|
||||||
|
// must match the type from the existing state.
|
||||||
|
//
|
||||||
|
eng::string apply_lua(LuaCoreStack &LS0, LuaSlot tab, bool setpersist);
|
||||||
|
|
||||||
|
// Convert an animstate to a lua table.
|
||||||
|
//
|
||||||
|
// You can either convert the persistent key-value pairs, or the
|
||||||
|
// nonpersistent. So you'll need two lua tables to store both.
|
||||||
|
//
|
||||||
|
void to_lua(LuaCoreStack &LS, LuaSlot tab, bool persistent);
|
||||||
|
|
||||||
|
// Parse a string, for unit testing.
|
||||||
|
//
|
||||||
|
void parse(std::string_view s);
|
||||||
|
void clear_and_parse(std::string_view s);
|
||||||
|
|
||||||
|
// Constructor from an encoded string.
|
||||||
|
//
|
||||||
|
AnimState(std::string_view s) { decode(s); }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AnimCoreState
|
||||||
|
{
|
||||||
|
util::DXYZ xyz;
|
||||||
|
eng::string plane;
|
||||||
|
|
||||||
|
void decode(std::string_view enc);
|
||||||
|
};
|
||||||
|
|
||||||
|
class AnimQueue : public eng::nevernew {
|
||||||
|
private:
|
||||||
|
struct Step {
|
||||||
|
Step() { hash=0; }
|
||||||
|
Step(const eng::string &e, uint64_t h) : encoding(e), hash(h) {}
|
||||||
|
eng::string encoding;
|
||||||
|
uint64_t hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Construct an empty animation queue.
|
||||||
|
// clears the state to a valid state.
|
||||||
|
//
|
||||||
|
AnimQueue();
|
||||||
|
|
||||||
|
// Size limit.
|
||||||
|
//
|
||||||
int32_t size_limit() const { return size_limit_; }
|
int32_t size_limit() const { return size_limit_; }
|
||||||
int64_t version_number() const { return version_number_; }
|
|
||||||
bool version_identical(const AnimQueue &aq) const;
|
|
||||||
|
|
||||||
// Return true if the size limit and steps are identical.
|
// Clear and set the initial state.
|
||||||
bool size_and_steps_equal(const AnimQueue &aq) const;
|
//
|
||||||
|
void clear();
|
||||||
|
void clear(const AnimState &initial);
|
||||||
|
|
||||||
// Mutator to create a new step.
|
// Set the size limit. Must be 2-250
|
||||||
void add(int64_t id, const AnimStep &step);
|
//
|
||||||
|
void set_limit(int n);
|
||||||
|
|
||||||
// Clear and set the plane.
|
// Add an animation step.
|
||||||
void clear(const eng::string &plane);
|
//
|
||||||
|
// Note: add does not automatically compose the step with the previous
|
||||||
|
// step, you have to do that yourself.
|
||||||
|
//
|
||||||
|
void add(const AnimState &state);
|
||||||
|
|
||||||
// Serialize or deserialize to a StreamBuffer
|
// Serialize or deserialize to a StreamBuffer
|
||||||
//
|
//
|
||||||
// Caution: version numbers are not stored. On deserialize,
|
|
||||||
// version number is set to zero.
|
|
||||||
//
|
|
||||||
void serialize(StreamBuffer *sb) const;
|
void serialize(StreamBuffer *sb) const;
|
||||||
void deserialize(StreamBuffer *sb);
|
void deserialize(StreamBuffer *sb);
|
||||||
|
|
||||||
// Difference transmission
|
// Difference transmission
|
||||||
|
//
|
||||||
bool diff(const AnimQueue &auth, StreamBuffer *sb) const;
|
bool diff(const AnimQueue &auth, StreamBuffer *sb) const;
|
||||||
void patch(StreamBuffer *sb, DebugCollector *dbc);
|
void patch(StreamBuffer *sb, DebugCollector *dbc);
|
||||||
void update_version(const AnimQueue &auth);
|
|
||||||
|
|
||||||
// Get the final resting place after all animations are complete.
|
// Check for exactly equal. This does the full check of all
|
||||||
const AnimStep &back() const;
|
// fields, it is used exclusively for debugging.
|
||||||
|
|
||||||
public:
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
//
|
||||||
// TESTING SUPPORT
|
bool exactly_equal(const AnimQueue &aq) const;
|
||||||
|
|
||||||
|
// Check for exactly equal (fast). Compares the size, limit,
|
||||||
|
// and hash of the last entry. If these are equal, then the whole
|
||||||
|
// thing should be equal.
|
||||||
//
|
//
|
||||||
// The following functions are not designed to be useful for production
|
bool exactly_equal_fast(const AnimQueue &aq) const;
|
||||||
// code, they're designed to be helpful for unit testing.
|
|
||||||
|
// Debug strings.
|
||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Change the size limit.
|
|
||||||
void full_clear_and_set_limit(int szl);
|
|
||||||
void set_limit(int szl);
|
|
||||||
|
|
||||||
// Make sure the invariants are preserved.
|
|
||||||
bool valid() const;
|
|
||||||
|
|
||||||
// Convert to a string for debugging purposes.
|
|
||||||
eng::string steps_debug_string() const;
|
eng::string steps_debug_string() const;
|
||||||
eng::string full_debug_string() const;
|
eng::string full_debug_string() const;
|
||||||
|
|
||||||
// Convert to a
|
// Get the final entry, xyz and plane only.
|
||||||
|
//
|
||||||
|
AnimCoreState get_final_core_state() const;
|
||||||
|
|
||||||
|
// Get the final entry, all persistent variables.
|
||||||
|
//
|
||||||
|
AnimState get_final_persistent() const;
|
||||||
|
|
||||||
|
// Get the final entry, everything persistent and non-persistent.
|
||||||
|
//
|
||||||
|
AnimState get_final_everything() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool version_autoinc_;
|
int size_limit_;
|
||||||
int32_t size_limit_;
|
eng::deque<Step> steps_;
|
||||||
eng::deque<AnimStep> steps_;
|
|
||||||
int64_t version_number_;
|
|
||||||
|
|
||||||
// Called whenever the animation queue is mutated.
|
|
||||||
// serialization and deserialization
|
|
||||||
void mutated();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ANIMQUEUE_HPP
|
#endif // ANIMQUEUE_HPP
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "wrap-vector.hpp"
|
#include "wrap-vector.hpp"
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
#include "drivenengine.hpp"
|
#include "drivenengine.hpp"
|
||||||
|
#include "world.hpp"
|
||||||
|
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@@ -138,6 +139,11 @@ void DrivenEngine::rescan_lua_source() {
|
|||||||
rescan_lua_source_ = true;
|
rescan_lua_source_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DrivenEngine::set_visible_world_and_actor(World *w, int64_t id) {
|
||||||
|
visible_world_ = w;
|
||||||
|
visible_actor_id_ = id;
|
||||||
|
}
|
||||||
|
|
||||||
void DrivenEngine::stop_driver() {
|
void DrivenEngine::stop_driver() {
|
||||||
stop_driver_ = true;
|
stop_driver_ = true;
|
||||||
for (int i = 0; i < DRV_MAX_CHAN; i++) {
|
for (int i = 0; i < DRV_MAX_CHAN; i++) {
|
||||||
@@ -190,8 +196,8 @@ inline static const char *action_string(DrvAction act) {
|
|||||||
case PLAY_RECV_INCOMING: return "PLAY_RECV_INCOMING";
|
case PLAY_RECV_INCOMING: return "PLAY_RECV_INCOMING";
|
||||||
case PLAY_NOTIFY_CLOSE: return "PLAY_NOTIFY_CLOSE";
|
case PLAY_NOTIFY_CLOSE: return "PLAY_NOTIFY_CLOSE";
|
||||||
case PLAY_NOTIFY_ACCEPT: return "PLAY_NOTIFY_ACCEPT";
|
case PLAY_NOTIFY_ACCEPT: return "PLAY_NOTIFY_ACCEPT";
|
||||||
case PLAY_SET_LUA_SOURCE: return "PLAY_SET_LUA_SOURCE";
|
|
||||||
case PLAY_INVOKE_EVENT_UPDATE: return "PLAY_INVOKE_EVENT_UPDATE";
|
case PLAY_INVOKE_EVENT_UPDATE: return "PLAY_INVOKE_EVENT_UPDATE";
|
||||||
|
case PLAY_SET_LUA_SOURCE: return "PLAY_SET_LUA_SOURCE";
|
||||||
case PLAY_RELEASE: return "PLAY_RELEASE";
|
case PLAY_RELEASE: return "PLAY_RELEASE";
|
||||||
default: return "unknown";
|
default: return "unknown";
|
||||||
}
|
}
|
||||||
@@ -403,6 +409,30 @@ bool DrivenEngine::drv_get_stop_driver() const {
|
|||||||
return stop_driver_;
|
return stop_driver_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t DrivenEngine::drv_get_actor_id() const {
|
||||||
|
return visible_actor_id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrivenEngine::drv_get_tangibles_near(uint64_t tanid, double rx, double ry, double rz, uint32_t *count, int64_t **ids) {
|
||||||
|
scan_result_.clear();
|
||||||
|
if ((visible_world_ != 0) && (tanid != 0)) {
|
||||||
|
PlaneScan scan;
|
||||||
|
scan.set_near(tanid, true);
|
||||||
|
scan.set_omit_nowhere(true);
|
||||||
|
scan.set_sorted(false);
|
||||||
|
scan.set_radius(util::XYZ(rx, ry, rz));
|
||||||
|
scan.set_shape(PlaneScan::CYLINDER);
|
||||||
|
visible_world_->get_near(scan, &scan_result_);
|
||||||
|
}
|
||||||
|
*count = scan_result_.size();
|
||||||
|
if (*count > 0) {
|
||||||
|
*ids = &scan_result_[0];
|
||||||
|
} else {
|
||||||
|
*ids = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
@@ -465,6 +495,8 @@ void DrivenEngine::drv_set_lua_source(uint32_t srcpklen, const char *srcpk) {
|
|||||||
rescan_lua_source_ = false;
|
rescan_lua_source_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
@@ -522,6 +554,15 @@ static bool drv_get_stop_driver(EngineWrapper *w) {
|
|||||||
return w->engine->drv_get_stop_driver();
|
return w->engine->drv_get_stop_driver();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint64_t drv_get_actor_id(EngineWrapper *w) {
|
||||||
|
return w->engine->drv_get_actor_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void drv_get_tangibles_near(EngineWrapper *w, uint64_t tanid, double rx, double ry, double rz, uint32_t *count, int64_t **ids) {
|
||||||
|
return w->engine->drv_get_tangibles_near(tanid, rx, ry, rz, count, ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
@@ -798,6 +839,7 @@ void replay_set_lua_source(EngineWrapper *w) {
|
|||||||
w->engine->drv_set_lua_source(srcpack.size(), srcpack.c_str());
|
w->engine->drv_set_lua_source(srcpack.size(), srcpack.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
@@ -864,21 +906,13 @@ static void replaycore_step(EngineWrapper *w) {
|
|||||||
case PLAY_RECV_INCOMING: replay_recv_incoming(w); return;
|
case PLAY_RECV_INCOMING: replay_recv_incoming(w); return;
|
||||||
case PLAY_NOTIFY_CLOSE: replay_notify_close(w); return;
|
case PLAY_NOTIFY_CLOSE: replay_notify_close(w); return;
|
||||||
case PLAY_NOTIFY_ACCEPT: replay_notify_accept(w); return;
|
case PLAY_NOTIFY_ACCEPT: replay_notify_accept(w); return;
|
||||||
case PLAY_SET_LUA_SOURCE: replay_set_lua_source(w); return;
|
|
||||||
case PLAY_INVOKE_EVENT_UPDATE: replay_invoke_event_update(w); return;
|
case PLAY_INVOKE_EVENT_UPDATE: replay_invoke_event_update(w); return;
|
||||||
|
case PLAY_SET_LUA_SOURCE: replay_set_lua_source(w); return;
|
||||||
case PLAY_RELEASE: release(w); return;
|
case PLAY_RELEASE: release(w); return;
|
||||||
default: return reset_wrapper(w, "Replay log corrupt in command dispatcher");
|
default: return reset_wrapper(w, "Replay log corrupt in command dispatcher");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// General Mutators
|
|
||||||
//
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -923,6 +957,8 @@ static void init_engine_wrapper_helper(EngineWrapper *w) {
|
|||||||
w->get_clock = drv_get_clock;
|
w->get_clock = drv_get_clock;
|
||||||
w->get_rescan_lua_source = drv_get_rescan_lua_source;
|
w->get_rescan_lua_source = drv_get_rescan_lua_source;
|
||||||
w->get_stop_driver = drv_get_stop_driver;
|
w->get_stop_driver = drv_get_stop_driver;
|
||||||
|
w->get_actor_id = drv_get_actor_id;
|
||||||
|
w->get_tangibles_near = drv_get_tangibles_near;
|
||||||
|
|
||||||
w->play_initialize = play_initialize;
|
w->play_initialize = play_initialize;
|
||||||
w->play_clear_new_outgoing = play_clear_new_outgoing;
|
w->play_clear_new_outgoing = play_clear_new_outgoing;
|
||||||
|
|||||||
@@ -52,8 +52,10 @@
|
|||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
#include "streambuffer.hpp"
|
#include "streambuffer.hpp"
|
||||||
#include "enginewrapper.hpp"
|
#include "enginewrapper.hpp"
|
||||||
|
#include "planemap.hpp"
|
||||||
|
|
||||||
class DrivenEngine;
|
class DrivenEngine;
|
||||||
|
class World;
|
||||||
using UniqueDrivenEngine = std::unique_ptr<DrivenEngine>;
|
using UniqueDrivenEngine = std::unique_ptr<DrivenEngine>;
|
||||||
using DrivenEngineMaker = UniqueDrivenEngine (*)();
|
using DrivenEngineMaker = UniqueDrivenEngine (*)();
|
||||||
using DrivenEngineInitializer = void (*)();
|
using DrivenEngineInitializer = void (*)();
|
||||||
@@ -222,6 +224,14 @@ public:
|
|||||||
//
|
//
|
||||||
void rescan_lua_source();
|
void rescan_lua_source();
|
||||||
|
|
||||||
|
// Set the world pointer and the actor ID.
|
||||||
|
//
|
||||||
|
// This allows the graphics engine to query the DrivenEngine
|
||||||
|
// about the state of the world and the player. It is legal to set these
|
||||||
|
// to zero, in which case queries will return null results.
|
||||||
|
//
|
||||||
|
void set_visible_world_and_actor(World *w, int64_t actor);
|
||||||
|
|
||||||
// Stop the driver. The engine should call this when it's done
|
// Stop the driver. The engine should call this when it's done
|
||||||
// and there's nothing left to do.
|
// and there's nothing left to do.
|
||||||
//
|
//
|
||||||
@@ -270,6 +280,8 @@ public:
|
|||||||
double drv_get_clock() const;
|
double drv_get_clock() const;
|
||||||
bool drv_get_rescan_lua_source() const;
|
bool drv_get_rescan_lua_source() const;
|
||||||
bool drv_get_stop_driver() const;
|
bool drv_get_stop_driver() const;
|
||||||
|
uint64_t drv_get_actor_id() const;
|
||||||
|
void drv_get_tangibles_near(uint64_t tanid, double rx, double ry, double rz, uint32_t *count, int64_t **ids);
|
||||||
|
|
||||||
void drv_initialize(uint32_t srcpklen, const char *srcpk, int argc, char **argv);
|
void drv_initialize(uint32_t srcpklen, const char *srcpk, int argc, char **argv);
|
||||||
void drv_clear_new_outgoing();
|
void drv_clear_new_outgoing();
|
||||||
@@ -296,6 +308,9 @@ private:
|
|||||||
eng::vector<uint32_t> new_outgoing_;
|
eng::vector<uint32_t> new_outgoing_;
|
||||||
util::LuaSourcePtr lua_source_;
|
util::LuaSourcePtr lua_source_;
|
||||||
eng::vector<uint32_t> listen_ports_;
|
eng::vector<uint32_t> listen_ports_;
|
||||||
|
World *visible_world_;
|
||||||
|
int64_t visible_actor_id_;
|
||||||
|
util::IdVector scan_result_;
|
||||||
bool rescan_lua_source_;
|
bool rescan_lua_source_;
|
||||||
double clock_;
|
double clock_;
|
||||||
bool stop_driver_;
|
bool stop_driver_;
|
||||||
|
|||||||
@@ -110,6 +110,14 @@ struct EngineWrapper {
|
|||||||
//
|
//
|
||||||
bool (*get_stop_driver)(EngineWrapper *w);
|
bool (*get_stop_driver)(EngineWrapper *w);
|
||||||
|
|
||||||
|
// Get the actor ID. May return zero if the server is down.
|
||||||
|
//
|
||||||
|
uint64_t (*get_actor_id)(EngineWrapper *w);
|
||||||
|
|
||||||
|
// Get the results of the last scan radius.
|
||||||
|
//
|
||||||
|
void (*get_tangibles_near)(EngineWrapper *w, uint64_t tanid, double rx, double ry, double rz, uint32_t *count, int64_t **ids);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -52,6 +52,9 @@ public:
|
|||||||
|
|
||||||
// Set the console prompt.
|
// Set the console prompt.
|
||||||
set_console_prompt(console_.get_prompt());
|
set_console_prompt(console_.get_prompt());
|
||||||
|
|
||||||
|
// Export stuff to the graphics engine.
|
||||||
|
set_visible_world_and_actor(master_.get(), admin_id_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_luainvoke_command(const util::StringVec &words) {
|
void do_luainvoke_command(const util::StringVec &words) {
|
||||||
|
|||||||
@@ -94,6 +94,10 @@ void LuaConsole::simplify(const StringVec &words) {
|
|||||||
if (words.size() != 1) {
|
if (words.size() != 1) {
|
||||||
synerr("/work takes no arguments");
|
synerr("/work takes no arguments");
|
||||||
}
|
}
|
||||||
|
} else if (words[0] == "display") {
|
||||||
|
if (words.size() != 1) {
|
||||||
|
synerr("/display takes no arguments");
|
||||||
|
}
|
||||||
} else if (words[0] == "aborthttp") {
|
} else if (words[0] == "aborthttp") {
|
||||||
if (words.size() != 1) {
|
if (words.size() != 1) {
|
||||||
synerr("/aborthttp takes no arguments");
|
synerr("/aborthttp takes no arguments");
|
||||||
|
|||||||
@@ -224,13 +224,12 @@ public:
|
|||||||
|
|
||||||
using NodeID = uint64_t;
|
using NodeID = uint64_t;
|
||||||
using ChildBits = uint64_t;
|
using ChildBits = uint64_t;
|
||||||
using IdVector = util::IdVector;
|
|
||||||
|
|
||||||
// The PlaneMap that this tree is a part of.
|
// The PlaneMap that this tree is a part of.
|
||||||
PlaneMap *planemap_;
|
PlaneMap *planemap_;
|
||||||
|
|
||||||
// The name of this plane.
|
// The name of this plane.
|
||||||
eng::string plane_;
|
std::string plane_;
|
||||||
|
|
||||||
// Internal nodes in the tree just have bits indicating
|
// Internal nodes in the tree just have bits indicating
|
||||||
// which children exist.
|
// which children exist.
|
||||||
@@ -440,7 +439,7 @@ public:
|
|||||||
(*os) << "| ";
|
(*os) << "| ";
|
||||||
print_node_id(node, os);
|
print_node_id(node, os);
|
||||||
(*os) << " ";
|
(*os) << " ";
|
||||||
util::IdVector ids;
|
IdVector ids;
|
||||||
collect_planeitem_ids(first, &ids);
|
collect_planeitem_ids(first, &ids);
|
||||||
std::sort(ids.begin(), ids.end());
|
std::sort(ids.begin(), ids.end());
|
||||||
util::print_id_vector(ids, os);
|
util::print_id_vector(ids, os);
|
||||||
@@ -667,7 +666,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Construct a PlaneTree.
|
// Construct a PlaneTree.
|
||||||
PlaneTree(PlaneMap *pmap, const eng::string &plane) {
|
PlaneTree(PlaneMap *pmap, std::string_view plane) {
|
||||||
planemap_ = pmap;
|
planemap_ = pmap;
|
||||||
plane_ = plane;
|
plane_ = plane;
|
||||||
total_count_ = 0;
|
total_count_ = 0;
|
||||||
@@ -779,30 +778,29 @@ PlaneMap::PlaneMap() : default_radius_(32768.0) {}
|
|||||||
PlaneMap::~PlaneMap() {}
|
PlaneMap::~PlaneMap() {}
|
||||||
|
|
||||||
|
|
||||||
IdVector PlaneMap::scan(const PlaneScan &sc) const {
|
void PlaneMap::scan(const PlaneScan &sc, util::IdVector *into) const {
|
||||||
IdVector result;
|
into->clear();
|
||||||
int startpos = 0;
|
int startpos = 0;
|
||||||
if (sc.near_ != 0) {
|
if (sc.near_ != 0) {
|
||||||
if (sc.include_near_) {
|
if (sc.include_near_) {
|
||||||
result.push_back(sc.near_);
|
into->push_back(sc.near_);
|
||||||
startpos = 1;
|
startpos = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sc.omit_nowhere_ && (sc.plane_ == "nowhere")) {
|
if (sc.omit_nowhere_ && (sc.plane_ == "nowhere")) {
|
||||||
return result;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto piter = planes_.find(sc.plane_);
|
auto piter = planes_.find(std::string_view(sc.plane_));
|
||||||
if (piter != planes_.end()) {
|
if (piter != planes_.end()) {
|
||||||
const std::unique_ptr<PlaneTree> &tree = piter->second;
|
const std::unique_ptr<PlaneTree> &tree = piter->second;
|
||||||
tree->scan(sc, &result, nullptr);
|
tree->scan(sc, into, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sc.sorted_) {
|
if (sc.sorted_) {
|
||||||
std::sort(result.begin() + startpos, result.end());
|
std::sort(into->begin() + startpos, into->end());
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
eng::string PlaneMap::tree_debug_string(const eng::string &plane) {
|
eng::string PlaneMap::tree_debug_string(const eng::string &plane) {
|
||||||
@@ -814,11 +812,11 @@ eng::string PlaneMap::outliers_debug_string(const eng::string &plane) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
eng::string PlaneMap::search_bboxes_debug_string(const PlaneScan &scan) {
|
eng::string PlaneMap::search_bboxes_debug_string(const PlaneScan &scan) {
|
||||||
return PlaneTree::get(this, scan.plane_)->search_bboxes_debug_string(scan);
|
return PlaneTree::get(this, eng::string(scan.plane_))->search_bboxes_debug_string(scan);
|
||||||
}
|
}
|
||||||
|
|
||||||
eng::string PlaneMap::scan_steps_debug_string(const PlaneScan &scan) {
|
eng::string PlaneMap::scan_steps_debug_string(const PlaneScan &scan) {
|
||||||
return PlaneTree::get(this, scan.plane_)->scan_steps_debug_string(scan);
|
return PlaneTree::get(this, eng::string(scan.plane_))->scan_steps_debug_string(scan);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlaneMap::untrack_all() {
|
void PlaneMap::untrack_all() {
|
||||||
@@ -1161,7 +1159,7 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
|||||||
// The two corners are deliberately not in low-high order.
|
// The two corners are deliberately not in low-high order.
|
||||||
scan.clear();
|
scan.clear();
|
||||||
scan.set_plane("p");
|
scan.set_plane("p");
|
||||||
scan.set_bbox_given_center_radius(util::XYZ(0x23, 0x97, 0x103), 2.0f);
|
scan.set_center_and_radius(util::XYZ(0x23, 0x97, 0x103), 2.0f);
|
||||||
LuaAssertStrEq(L, pm.search_bboxes_debug_string(scan),
|
LuaAssertStrEq(L, pm.search_bboxes_debug_string(scan),
|
||||||
"|Level 8 0,0,0 - 0,0,0"
|
"|Level 8 0,0,0 - 0,0,0"
|
||||||
"|Level 6 8,8,8 - 8,8,8"
|
"|Level 6 8,8,8 - 8,8,8"
|
||||||
@@ -1181,7 +1179,7 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
|||||||
// sure they only include the one cell.
|
// sure they only include the one cell.
|
||||||
scan.clear();
|
scan.clear();
|
||||||
scan.set_plane("p");
|
scan.set_plane("p");
|
||||||
scan.set_bbox_given_center_radius(util::XYZ(0x12, 0x34, 0x45), 0.0);
|
scan.set_center_and_radius(util::XYZ(0x12, 0x34, 0x45), 0.0);
|
||||||
LuaAssertStrEq(L, pm.search_bboxes_debug_string(scan),
|
LuaAssertStrEq(L, pm.search_bboxes_debug_string(scan),
|
||||||
"|Level 8 0,0,0 - 0,0,0"
|
"|Level 8 0,0,0 - 0,0,0"
|
||||||
"|Level 6 8,8,8 - 8,8,8"
|
"|Level 6 8,8,8 - 8,8,8"
|
||||||
@@ -1207,7 +1205,7 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
|||||||
// from one cell to the next.
|
// from one cell to the next.
|
||||||
scan.clear();
|
scan.clear();
|
||||||
scan.set_plane("p");
|
scan.set_plane("p");
|
||||||
scan.set_bbox_given_center_radius(util::XYZ(0x12 + 0.5, 0x34, 0x45), 0.0);
|
scan.set_center_and_radius(util::XYZ(0x12 + 0.5, 0x34, 0x45), 0.0);
|
||||||
LuaAssertStrEq(L, pm.search_bboxes_debug_string(scan),
|
LuaAssertStrEq(L, pm.search_bboxes_debug_string(scan),
|
||||||
"|Level 8 0,0,0 - 0,0,0"
|
"|Level 8 0,0,0 - 0,0,0"
|
||||||
"|Level 6 8,8,8 - 8,8,8"
|
"|Level 6 8,8,8 - 8,8,8"
|
||||||
@@ -1235,7 +1233,7 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
|||||||
// to make sure they cover the entire PlaneTree.
|
// to make sure they cover the entire PlaneTree.
|
||||||
scan.clear();
|
scan.clear();
|
||||||
scan.set_plane("p");
|
scan.set_plane("p");
|
||||||
scan.set_bbox_given_center_radius(util::XYZ(0x12, 0x34, 0x45), 100000.0);
|
scan.set_center_and_radius(util::XYZ(0x12, 0x34, 0x45), 100000.0);
|
||||||
LuaAssertStrEq(L, pm.search_bboxes_debug_string(scan),
|
LuaAssertStrEq(L, pm.search_bboxes_debug_string(scan),
|
||||||
"|Level 8 0,0,0 - 0,0,0"
|
"|Level 8 0,0,0 - 0,0,0"
|
||||||
"|Level 6 0,0,0 - f,f,f"
|
"|Level 6 0,0,0 - f,f,f"
|
||||||
@@ -1292,7 +1290,7 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
|||||||
scan.clear();
|
scan.clear();
|
||||||
scan.set_plane("p");
|
scan.set_plane("p");
|
||||||
scan.set_shape(PlaneScan::SPHERE);
|
scan.set_shape(PlaneScan::SPHERE);
|
||||||
scan.set_bbox_given_center_radius(util::XYZ(0x12 + 0.1, 0x34, 0x45), 0.0);
|
scan.set_center_and_radius(util::XYZ(0x12 + 0.1, 0x34, 0x45), 0.0);
|
||||||
LuaAssertStrEq(L, pm.scan_steps_debug_string(scan),
|
LuaAssertStrEq(L, pm.scan_steps_debug_string(scan),
|
||||||
"|L8:root"
|
"|L8:root"
|
||||||
"| L7:2,2,2"
|
"| L7:2,2,2"
|
||||||
@@ -1350,7 +1348,7 @@ LuaDefine(unittests_planemap, "", "some unit tests") {
|
|||||||
// because the radius is nonzero.
|
// because the radius is nonzero.
|
||||||
scan.clear();
|
scan.clear();
|
||||||
scan.set_plane("p");
|
scan.set_plane("p");
|
||||||
scan.set_bbox_given_center_radius(util::XYZ(0x100000, 0x16, 0x23), 0.2);
|
scan.set_center_and_radius(util::XYZ(0x100000, 0x16, 0x23), 0.2);
|
||||||
LuaAssertStrEq(L, pm.search_bboxes_debug_string(scan),
|
LuaAssertStrEq(L, pm.search_bboxes_debug_string(scan),
|
||||||
"|Level 8 0,0,0 - 0,0,0"
|
"|Level 8 0,0,0 - 0,0,0"
|
||||||
"|Level 6 f,8,8 - f,8,8"
|
"|Level 6 f,8,8 - f,8,8"
|
||||||
|
|||||||
@@ -87,6 +87,7 @@
|
|||||||
class PlaneMap;
|
class PlaneMap;
|
||||||
class PlaneTree;
|
class PlaneTree;
|
||||||
|
|
||||||
|
|
||||||
class PlaneScan : public eng::nevernew {
|
class PlaneScan : public eng::nevernew {
|
||||||
public:
|
public:
|
||||||
friend class PlaneMap;
|
friend class PlaneMap;
|
||||||
@@ -94,7 +95,11 @@ public:
|
|||||||
enum Shape { BOX, CYLINDER, SPHERE };
|
enum Shape { BOX, CYLINDER, SPHERE };
|
||||||
private:
|
private:
|
||||||
// The plane to scan.
|
// The plane to scan.
|
||||||
eng::string plane_;
|
//
|
||||||
|
// Note: the reason this uses std::string instead of eng::string
|
||||||
|
// is that we want plane scans to not touch the engine heap.
|
||||||
|
//
|
||||||
|
std::string plane_;
|
||||||
|
|
||||||
// The bounding box of the scan.
|
// The bounding box of the scan.
|
||||||
util::XYZ center_, radius_;
|
util::XYZ center_, radius_;
|
||||||
@@ -119,13 +124,14 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
void clear() {
|
void clear() {
|
||||||
plane_ = "";
|
plane_.clear();
|
||||||
shape_ = BOX;
|
shape_ = BOX;
|
||||||
sorted_ = true;
|
sorted_ = true;
|
||||||
near_ = 0;
|
near_ = 0;
|
||||||
include_near_ = false;
|
include_near_ = false;
|
||||||
omit_nowhere_ = false;
|
omit_nowhere_ = false;
|
||||||
radius_ = center_ = util::XYZ();
|
radius_ = util::XYZ();
|
||||||
|
center_ = util::XYZ();
|
||||||
}
|
}
|
||||||
PlaneScan() { clear(); }
|
PlaneScan() { clear(); }
|
||||||
|
|
||||||
@@ -143,7 +149,7 @@ public:
|
|||||||
//
|
//
|
||||||
void configure(LuaKeywordParser &kw);
|
void configure(LuaKeywordParser &kw);
|
||||||
|
|
||||||
void set_bbox_given_center_radius(const util::XYZ ¢er, float r) {
|
void set_center_and_radius(const util::XYZ ¢er, float r) {
|
||||||
set_center(center);
|
set_center(center);
|
||||||
set_radius(r);
|
set_radius(r);
|
||||||
}
|
}
|
||||||
@@ -204,12 +210,12 @@ public:
|
|||||||
class PlaneMap : public eng::nevernew {
|
class PlaneMap : public eng::nevernew {
|
||||||
friend class PlaneItem;
|
friend class PlaneItem;
|
||||||
friend class PlaneTree;
|
friend class PlaneTree;
|
||||||
public:
|
|
||||||
using IdVector = util::IdVector;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float default_radius_;
|
float default_radius_;
|
||||||
eng::map<eng::string, std::unique_ptr<PlaneTree>> planes_;
|
|
||||||
|
// Plane Trees table.
|
||||||
|
//
|
||||||
|
eng::map<eng::string, std::unique_ptr<PlaneTree>, std::less<>> planes_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// No special code is needed for construction or destruction.
|
// No special code is needed for construction or destruction.
|
||||||
@@ -220,7 +226,11 @@ public:
|
|||||||
// PlaneItem. See PlaneItem::track and PlaneItem::untrack.
|
// PlaneItem. See PlaneItem::track and PlaneItem::untrack.
|
||||||
|
|
||||||
// Scan the PlaneMap for items, return their IDs.
|
// Scan the PlaneMap for items, return their IDs.
|
||||||
IdVector scan(const PlaneScan &s) const;
|
//
|
||||||
|
// Note: the reason this uses IdVector instead of IdVector
|
||||||
|
// is that we want scans to not touch the engine heap.
|
||||||
|
//
|
||||||
|
void scan(const PlaneScan &sc, util::IdVector *into) const;
|
||||||
|
|
||||||
// Set the default radius for all planes.
|
// Set the default radius for all planes.
|
||||||
// Maybe we'll make it adaptive some day.
|
// Maybe we'll make it adaptive some day.
|
||||||
|
|||||||
@@ -281,6 +281,26 @@ void StreamBuffer::write_double(double d) {
|
|||||||
write_cursor_ += 8;
|
write_cursor_ += 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StreamBuffer::write_xyz(const util::XYZ &xyz) {
|
||||||
|
make_space(12);
|
||||||
|
memcpy(write_cursor_, &xyz.x, 4);
|
||||||
|
write_cursor_ += 4;
|
||||||
|
memcpy(write_cursor_, &xyz.y, 4);
|
||||||
|
write_cursor_ += 4;
|
||||||
|
memcpy(write_cursor_, &xyz.z, 4);
|
||||||
|
write_cursor_ += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StreamBuffer::write_dxyz(const util::DXYZ &xyz) {
|
||||||
|
make_space(24);
|
||||||
|
memcpy(write_cursor_, &xyz.x, 8);
|
||||||
|
write_cursor_ += 8;
|
||||||
|
memcpy(write_cursor_, &xyz.y, 8);
|
||||||
|
write_cursor_ += 8;
|
||||||
|
memcpy(write_cursor_, &xyz.z, 8);
|
||||||
|
write_cursor_ += 8;
|
||||||
|
}
|
||||||
|
|
||||||
int8_t StreamBuffer::read_int8() {
|
int8_t StreamBuffer::read_int8() {
|
||||||
check_available(1);
|
check_available(1);
|
||||||
int8_t v;
|
int8_t v;
|
||||||
@@ -336,6 +356,32 @@ double StreamBuffer::read_double() {
|
|||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
util::XYZ StreamBuffer::read_xyz() {
|
||||||
|
check_available(12);
|
||||||
|
util::XYZ result;
|
||||||
|
memcpy(&result.x, read_cursor_, 4);
|
||||||
|
read_cursor_ += 4;
|
||||||
|
memcpy(&result.y, read_cursor_, 4);
|
||||||
|
read_cursor_ += 4;
|
||||||
|
memcpy(&result.z, read_cursor_, 4);
|
||||||
|
read_cursor_ += 4;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
util::DXYZ StreamBuffer::read_dxyz() {
|
||||||
|
check_available(24);
|
||||||
|
util::DXYZ result;
|
||||||
|
memcpy(&result.x, read_cursor_, 8);
|
||||||
|
read_cursor_ += 8;
|
||||||
|
memcpy(&result.y, read_cursor_, 8);
|
||||||
|
read_cursor_ += 8;
|
||||||
|
memcpy(&result.z, read_cursor_, 8);
|
||||||
|
read_cursor_ += 8;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void StreamBuffer::write_hashvalue(const util::HashValue &hv) {
|
void StreamBuffer::write_hashvalue(const util::HashValue &hv) {
|
||||||
write_uint64(hv.first);
|
write_uint64(hv.first);
|
||||||
write_uint64(hv.second);
|
write_uint64(hv.second);
|
||||||
|
|||||||
@@ -313,6 +313,8 @@ public:
|
|||||||
void write_char(char c);
|
void write_char(char c);
|
||||||
void write_float(float f);
|
void write_float(float f);
|
||||||
void write_double(double d);
|
void write_double(double d);
|
||||||
|
void write_xyz(const util::XYZ &xyz);
|
||||||
|
void write_dxyz(const util::DXYZ &xyz);
|
||||||
|
|
||||||
// Read fixed-size integers from the buffer.
|
// Read fixed-size integers from the buffer.
|
||||||
//
|
//
|
||||||
@@ -329,6 +331,8 @@ public:
|
|||||||
char read_char();
|
char read_char();
|
||||||
float read_float();
|
float read_float();
|
||||||
double read_double();
|
double read_double();
|
||||||
|
util::XYZ read_xyz();
|
||||||
|
util::DXYZ read_dxyz();
|
||||||
|
|
||||||
// Write other types into the buffer.
|
// Write other types into the buffer.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -494,6 +494,15 @@ void print_id_vector(const IdVector &idv, std::ostream *os) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void print_id_vector(const std::vector<uint64_t> &idv, std::ostream *os) {
|
||||||
|
bool first = true;
|
||||||
|
for (int64_t id : idv) {
|
||||||
|
if (!first) (*os) << ",";
|
||||||
|
(*os) << id;
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
eng::string id_vector_debug_string(const IdVector &idv) {
|
eng::string id_vector_debug_string(const IdVector &idv) {
|
||||||
eng::ostringstream oss;
|
eng::ostringstream oss;
|
||||||
print_id_vector(idv, &oss);
|
print_id_vector(idv, &oss);
|
||||||
@@ -518,10 +527,17 @@ IdVector sort_union_id_vectors(const IdVector &v1, const IdVector &v2) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
HashValue hash_string(const eng::string &s) {
|
HashValue hash_string(std::string_view s) {
|
||||||
uint64_t hash1 = 0;
|
uint64_t hash1 = 0;
|
||||||
uint64_t hash2 = 0;
|
uint64_t hash2 = 0;
|
||||||
SpookyHash::ChainHash128(s.c_str(), s.size(), &hash1, &hash2);
|
SpookyHash::ChainHash128(s.data(), s.size(), &hash1, &hash2);
|
||||||
|
return util::HashValue(hash1, hash2);
|
||||||
|
}
|
||||||
|
|
||||||
|
HashValue hash_string(HashValue prev, std::string_view s) {
|
||||||
|
uint64_t hash1 = prev.first;
|
||||||
|
uint64_t hash2 = prev.second;
|
||||||
|
SpookyHash::ChainHash128(s.data(), s.size(), &hash1, &hash2);
|
||||||
return util::HashValue(hash1, hash2);
|
return util::HashValue(hash1, hash2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -718,11 +734,6 @@ LuaSourcePtr make_lua_source(const eng::string &code) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
eng::string XYZ::debug_string() const {
|
|
||||||
eng::ostringstream oss;
|
|
||||||
oss << "(" << x << "," << y << "," << z << ")";
|
|
||||||
return oss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void (*dprint_hook)(const char *oneline, size_t size);
|
void (*dprint_hook)(const char *oneline, size_t size);
|
||||||
|
|||||||
@@ -211,13 +211,18 @@ enum MessageType {
|
|||||||
MSG_INVOKE,
|
MSG_INVOKE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Note: IdVector is weird in that it deliberately uses std::vector
|
||||||
|
// instead of eng::vector. This is because we want plane scans
|
||||||
|
// to not touch the engine heap.
|
||||||
|
//
|
||||||
|
using IdVector = std::vector<int64_t>;
|
||||||
|
|
||||||
using StringVec = eng::vector<eng::string>;
|
using StringVec = eng::vector<eng::string>;
|
||||||
using StringPair = std::pair<eng::string, eng::string>;
|
using StringPair = std::pair<eng::string, eng::string>;
|
||||||
using StringSet = eng::set<eng::string>;
|
using StringSet = eng::set<eng::string>;
|
||||||
using LuaSourceVec = eng::vector<StringPair>;
|
using LuaSourceVec = eng::vector<StringPair>;
|
||||||
using LuaSourcePtr = std::unique_ptr<LuaSourceVec>;
|
using LuaSourcePtr = std::unique_ptr<LuaSourceVec>;
|
||||||
using HashValue = std::pair<uint64_t, uint64_t>;
|
using HashValue = std::pair<uint64_t, uint64_t>;
|
||||||
using IdVector = eng::vector<int64_t>;
|
|
||||||
|
|
||||||
// Ascii uppercase and lowercase.
|
// Ascii uppercase and lowercase.
|
||||||
eng::string ascii_tolower(std::string_view c);
|
eng::string ascii_tolower(std::string_view c);
|
||||||
@@ -241,6 +246,7 @@ IdVector id_vector_create(int64_t id1=-1, int64_t id2=-1, int64_t id3=-1, int64_
|
|||||||
|
|
||||||
// Print an ID vector to a stream.
|
// Print an ID vector to a stream.
|
||||||
void print_id_vector(const IdVector &idv, std::ostream *os);
|
void print_id_vector(const IdVector &idv, std::ostream *os);
|
||||||
|
void print_id_vector(const std::vector<uint64_t> &idv, std::ostream *os);
|
||||||
|
|
||||||
// ID vector debug string.
|
// ID vector debug string.
|
||||||
eng::string id_vector_debug_string(const IdVector &idv);
|
eng::string id_vector_debug_string(const IdVector &idv);
|
||||||
@@ -249,7 +255,10 @@ eng::string id_vector_debug_string(const IdVector &idv);
|
|||||||
IdVector sort_union_id_vectors(const IdVector &v1, const IdVector &v2);
|
IdVector sort_union_id_vectors(const IdVector &v1, const IdVector &v2);
|
||||||
|
|
||||||
// Get a 128-bit hashvalue for a string.
|
// Get a 128-bit hashvalue for a string.
|
||||||
HashValue hash_string(const eng::string &str);
|
HashValue hash_string(std::string_view str);
|
||||||
|
|
||||||
|
// Get a 128-bit hashvalue for a string, with a previous value.
|
||||||
|
HashValue hash_string(HashValue prev, std::string_view str);
|
||||||
|
|
||||||
// Get a 128-bit hashvalue for an ID vector.
|
// Get a 128-bit hashvalue for an ID vector.
|
||||||
HashValue hash_id_vector(const IdVector &idv);
|
HashValue hash_id_vector(const IdVector &idv);
|
||||||
@@ -322,18 +331,32 @@ void remove_marked_items(T &vec) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// An XYZ coordinate, general purpose.
|
// An XYZ coordinate, general purpose.
|
||||||
struct XYZ {
|
template <typename NUMBER>
|
||||||
float x, y, z;
|
struct NumXYZ {
|
||||||
XYZ() { x=0; y=0; z=0; }
|
using Number = NUMBER;
|
||||||
XYZ(float ix, float iy, float iz) { x=ix; y=iy; z=iz; }
|
Number x, y, z;
|
||||||
bool operator ==(const XYZ &o) const { return x==o.x && y == o.y && z==o.z; }
|
NumXYZ() { x=0; y=0; z=0; }
|
||||||
bool operator !=(const XYZ &o) const { return x!=o.x || y != o.y || z!=o.z; }
|
NumXYZ(Number ix, Number iy, Number iz) { x=ix; y=iy; z=iz; }
|
||||||
XYZ operator -(const XYZ &o) const { return XYZ(x-o.x, y-o.y, z-o.z); }
|
void operator =(const NumXYZ &other) { x = other.x; y = other.y; z = other.z; }
|
||||||
XYZ operator +(const XYZ &o) const { return XYZ(x+o.x, y+o.y, z+o.z); }
|
void operator =(Number n) { x = n; y = n; z = n; }
|
||||||
XYZ operator *(float scale) const { return XYZ(x*scale, y*scale, z*scale); }
|
bool operator ==(const NumXYZ &o) const { return x==o.x && y == o.y && z==o.z; }
|
||||||
eng::string debug_string() const;
|
bool operator !=(const NumXYZ &o) const { return x!=o.x || y != o.y || z!=o.z; }
|
||||||
|
NumXYZ operator -(const NumXYZ &o) const { return NumXYZ(x-o.x, y-o.y, z-o.z); }
|
||||||
|
NumXYZ operator +(const NumXYZ &o) const { return NumXYZ(x+o.x, y+o.y, z+o.z); }
|
||||||
|
NumXYZ operator *(float scale) const { return NumXYZ(x*scale, y*scale, z*scale); }
|
||||||
|
template<typename ONUMBER>
|
||||||
|
const NumXYZ<ONUMBER> convert() const { NumXYZ<ONUMBER> r; r.x=ONUMBER(x); r.y=ONUMBER(y); r.z=ONUMBER(z); return r; }
|
||||||
|
|
||||||
|
eng::string debug_string() const {
|
||||||
|
eng::ostringstream oss;
|
||||||
|
oss << "(" << x << "," << y << "," << z << ")";
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using XYZ=NumXYZ<float>;
|
||||||
|
using DXYZ=NumXYZ<double>;
|
||||||
|
|
||||||
// util::ostringstream
|
// util::ostringstream
|
||||||
//
|
//
|
||||||
// This is a variant of ostringstream in which it is possible
|
// This is a variant of ostringstream in which it is possible
|
||||||
@@ -455,4 +478,9 @@ inline std::ostream &operator<<(std::ostream &oss, const util::XYZ &xyz) {
|
|||||||
return oss;
|
return oss;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::ostream &operator<<(std::ostream &oss, const util::DXYZ &xyz) {
|
||||||
|
oss << xyz.x << "," << xyz.y << "," << xyz.z;
|
||||||
|
return oss;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // UTIL_HPP
|
#endif // UTIL_HPP
|
||||||
|
|||||||
@@ -17,56 +17,169 @@ static void tangible_getall(LuaCoreStack &LS0, LuaSlot list, const util::IdVecto
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LuaDefine(tangible_animstate, "tan",
|
|
||||||
"|Get the entire animation state of the tangible."
|
|
||||||
"|Returns six values: graphic,plane,x,y,z,facing.") {
|
|
||||||
LuaArg tanobj;
|
|
||||||
LuaRet graphic, plane, x, y, z, facing;
|
|
||||||
LuaDefStack LS(L, tanobj, graphic, plane, x, y, z, facing);
|
|
||||||
World *w = World::fetch_global_pointer(L);
|
|
||||||
Tangible *tan = w->tangible_get(LS, tanobj, false);
|
|
||||||
const AnimStep &aqback = tan->anim_queue_.back();
|
|
||||||
LS.set(graphic, aqback.graphic());
|
|
||||||
LS.set(plane, aqback.plane());
|
|
||||||
LS.set(x, aqback.xyz().x);
|
|
||||||
LS.set(y, aqback.xyz().y);
|
|
||||||
LS.set(z, aqback.xyz().z);
|
|
||||||
LS.set(facing, aqback.facing());
|
|
||||||
return LS.result();
|
|
||||||
}
|
|
||||||
|
|
||||||
LuaDefine(tangible_xyz, "tan",
|
LuaDefine(tangible_xyz, "tan",
|
||||||
"|Get the current coordinates of the tangible."
|
"|Get the current coordinates of the tangible and the plane."
|
||||||
"|Returns three values: x, y, z") {
|
"|Returns four values: x, y, z, plane") {
|
||||||
LuaArg tanobj;
|
LuaArg tanobj;
|
||||||
LuaRet x, y, z;
|
LuaRet x, y, z, plane;
|
||||||
LuaDefStack LS(L, tanobj, x, y, z);
|
LuaDefStack LS(L, tanobj, x, y, z);
|
||||||
World *w = World::fetch_global_pointer(L);
|
World *w = World::fetch_global_pointer(L);
|
||||||
Tangible *tan = w->tangible_get(LS, tanobj, false);
|
Tangible *tan = w->tangible_get(LS, tanobj, false);
|
||||||
const AnimStep &aqback = tan->anim_queue_.back();
|
AnimCoreState pos = tan->anim_queue_.get_final_core_state();
|
||||||
LS.set(x, aqback.xyz().x);
|
LS.set(x, pos.xyz.x);
|
||||||
LS.set(y, aqback.xyz().y);
|
LS.set(y, pos.xyz.y);
|
||||||
LS.set(z, aqback.xyz().z);
|
LS.set(z, pos.xyz.z);
|
||||||
|
LS.set(plane, pos.plane);
|
||||||
return LS.result();
|
return LS.result();
|
||||||
}
|
}
|
||||||
|
|
||||||
LuaDefine(tangible_animate, "tan,configtable",
|
LuaDefine(tangible_animdebug, "tan",
|
||||||
"|Add an animation step to the tangible."
|
"|Return a debug string showing the entire animation queue"
|
||||||
"|The configtable is a table containing any of the following:"
|
"|") {
|
||||||
"|action,graphic,plane,x,y,z,facing") {
|
LuaArg tanobj;
|
||||||
LuaArg tanobj, config;
|
LuaRet result;
|
||||||
LuaDefStack LS(L, tanobj, config);
|
LuaDefStack LS(L, tanobj, result);
|
||||||
LuaKeywordParser kp(LS, config);
|
|
||||||
World *w = World::fetch_global_pointer(L);
|
World *w = World::fetch_global_pointer(L);
|
||||||
Tangible *tan = w->tangible_get(LS, tanobj, false);
|
Tangible *tan = w->tangible_get(LS, tanobj, false);
|
||||||
int64_t id = w->alloc_id_predictable();
|
LS.set(result, tan->anim_queue_.steps_debug_string());
|
||||||
AnimStep step;
|
return LS.result();
|
||||||
step.configure(kp, tan->anim_queue_.back());
|
}
|
||||||
kp.final_check_throw();
|
|
||||||
if (step.action() == "") {
|
LuaDefine(tangible_animstate, "tan",
|
||||||
luaL_error(L, "animation action must be specified");
|
"|Return the animation state variables of the tangible as a table."
|
||||||
|
"|"
|
||||||
|
"|The animation system stores 'animation state variables. "
|
||||||
|
"|There are several builtin animation state variables. The"
|
||||||
|
"|following is a list, along with some example values that"
|
||||||
|
"|might be used if the object were a pirate treasure chest."
|
||||||
|
"|"
|
||||||
|
"| xyz={1,2,3} # xyz coordinate"
|
||||||
|
"| plane='earth' # plane where the chest is located"
|
||||||
|
"| facing=0 # rotation of the chest"
|
||||||
|
"| bp='BP_piratechest' # name of an unreal blueprint"
|
||||||
|
"| model='SM_piratechest' # name of an unreal mesh"
|
||||||
|
"|"
|
||||||
|
"|There can also be user-defined animation state variables."
|
||||||
|
"|For example, for a pirate chest, you might want to add two"
|
||||||
|
"|more state variables:"
|
||||||
|
"|"
|
||||||
|
"| open=true # chest can be open or closed"
|
||||||
|
"| fullness=0.8 # how big the heap of coins is"
|
||||||
|
"|"
|
||||||
|
"|All state variables must be one of four types: number, string,"
|
||||||
|
"|boolean, or coordinate. All state variables must have simple"
|
||||||
|
"|identifiers for names."
|
||||||
|
"|"
|
||||||
|
"|Animation state variables are updated when you use"
|
||||||
|
"|tangible.animate to create an animation record. For example,"
|
||||||
|
"|suppose your character is initialized at xyz={1,1,1}. Then"
|
||||||
|
"|he walks to xyz={2,2,2}, then he walks to xyz={3,3,3}."
|
||||||
|
"|The animation queue now contains three animation steps:"
|
||||||
|
"|"
|
||||||
|
"|Animation Queue:"
|
||||||
|
"| Step 1: action:initialize xyz={1,1,1} ..."
|
||||||
|
"| Step 2: action:walkto xyz={2,2,2} ..."
|
||||||
|
"| Step 3: action:walkto xyz={3,3,3} ..."
|
||||||
|
"|"
|
||||||
|
"|Notice that the state variable xyz is stored three times, once"
|
||||||
|
"|in each animation step. All animation state variables are stored"
|
||||||
|
"|in every animation step. When you use tangible.animstate to fetch"
|
||||||
|
"|the current value of the animation state variables, you're"
|
||||||
|
"|actually fetching the state variables from the last step in"
|
||||||
|
"|the animation queue."
|
||||||
|
"|"
|
||||||
|
"|You can use this function, tangible.animstate, to view the"
|
||||||
|
"|current set of state variables. You can use tangible.animinit"
|
||||||
|
"|to reconfigure the set of user-defined state variables. You"
|
||||||
|
"|can use tangible.animate to create animation steps, which can"
|
||||||
|
"|alter any of the state variables."
|
||||||
|
"|") {
|
||||||
|
LuaArg tanobj;
|
||||||
|
LuaRet result;
|
||||||
|
LuaDefStack LS(L, tanobj, result);
|
||||||
|
World *w = World::fetch_global_pointer(L);
|
||||||
|
Tangible *tan = w->tangible_get(LS, tanobj, false);
|
||||||
|
AnimState state = tan->anim_queue_.get_final_persistent();
|
||||||
|
state.to_lua(LS, result, true);
|
||||||
|
return LS.result();
|
||||||
|
}
|
||||||
|
|
||||||
|
LuaDefine(tangible_animinit, "tan,config",
|
||||||
|
"|Reinitialize the animation queue."
|
||||||
|
"|"
|
||||||
|
"|The animation queue stores certain animation state variables."
|
||||||
|
"|See doc(tangible.animstate) for more information about animation"
|
||||||
|
"|state variables."
|
||||||
|
"|"
|
||||||
|
"|This function, tangible.animinit, is used to reconfigure the set of"
|
||||||
|
"|user-defined state variables. The config table that you pass in must"
|
||||||
|
"|be key-value pairs. Keys must be simple identifiers. Values can be"
|
||||||
|
"|numbers, strings, booleans, or coordinates."
|
||||||
|
"|"
|
||||||
|
"|After tangible.animinit, the tangible's animation state variables will"
|
||||||
|
"|consist of the user-defined variables listed in the config table,"
|
||||||
|
"|plus all the builtin animation state variables."
|
||||||
|
"|"
|
||||||
|
"|Optionally, the config table can also supply values for some or all"
|
||||||
|
"|of the builtin state variables. For example, you could supply xyz"
|
||||||
|
"|in the config table. If you do, the tangible will move to a new xyz"
|
||||||
|
"|coordinate. If not, the tangible will retain its old xyz coordinate."
|
||||||
|
"|") {
|
||||||
|
LuaArg tanobj, config;
|
||||||
|
LuaDefStack LS(L, tanobj, config);
|
||||||
|
World *w = World::fetch_global_pointer(L);
|
||||||
|
Tangible *tan = w->tangible_get(LS, tanobj, false);
|
||||||
|
AnimState state;
|
||||||
|
eng::string error = state.apply_lua(LS, config, true);
|
||||||
|
if (!error.empty()) {
|
||||||
|
luaL_error(L, "%s", error.c_str());
|
||||||
}
|
}
|
||||||
tan->anim_queue_.add(id, step);
|
AnimState defsource = tan->anim_queue_.get_final_persistent();
|
||||||
|
error = state.add_defaults(&defsource);
|
||||||
|
if (!error.empty()) {
|
||||||
|
luaL_error(L, "%s", error.c_str());
|
||||||
|
}
|
||||||
|
tan->anim_queue_.clear(state);
|
||||||
|
tan->update_plane_item();
|
||||||
|
return LS.result();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LuaDefine(tangible_animate, "tan,config",
|
||||||
|
"|Add an animation step to the tangible."
|
||||||
|
"|"
|
||||||
|
"|The animation queue stores animation steps. This function, "
|
||||||
|
"|tangible.animate, adds one new animation step to the queue."
|
||||||
|
"|"
|
||||||
|
"|It might be useful to read about 'animation state variables' before"
|
||||||
|
"|reading this explanation. See doc(tangible.animstate)."
|
||||||
|
"|"
|
||||||
|
"|An animation step is just a list of key-value pairs. Therefore,"
|
||||||
|
"|the config table must be key-value pairs. Keys must be simple"
|
||||||
|
"|identifiers. Values can be numbers, strings, booleans, or"
|
||||||
|
"|coordinates."
|
||||||
|
"|"
|
||||||
|
"|Some of the key-value pairs may match the name of an animation state"
|
||||||
|
"|variable. If so, that key-value pair permanently changes the"
|
||||||
|
"|value of that animation state variable. The new value will"
|
||||||
|
"|be retained for all future animation steps."
|
||||||
|
"|"
|
||||||
|
"|Some of the key-value pairs may NOT match the name of any animation"
|
||||||
|
"|state variable. If so, that key-value pair is part of the"
|
||||||
|
"|animation step, but nothing is propagated forward to future animation"
|
||||||
|
"|steps."
|
||||||
|
"|"
|
||||||
|
"|") {
|
||||||
|
LuaArg tanobj, config;
|
||||||
|
LuaDefStack LS(L, tanobj, config);
|
||||||
|
World *w = World::fetch_global_pointer(L);
|
||||||
|
Tangible *tan = w->tangible_get(LS, tanobj, false);
|
||||||
|
AnimState state = tan->anim_queue_.get_final_persistent();
|
||||||
|
eng::string error = state.apply_lua(LS, config, false);
|
||||||
|
if (!error.empty()) {
|
||||||
|
luaL_error(L, "%s", error.c_str());
|
||||||
|
}
|
||||||
|
tan->anim_queue_.add(state);
|
||||||
tan->update_plane_item();
|
tan->update_plane_item();
|
||||||
return LS.result();
|
return LS.result();
|
||||||
}
|
}
|
||||||
@@ -132,51 +245,53 @@ LuaDefine(tangible_delete, "tan",
|
|||||||
|
|
||||||
LuaDefine(tangible_build, "config",
|
LuaDefine(tangible_build, "config",
|
||||||
"|Build a new tangible object."
|
"|Build a new tangible object."
|
||||||
"|The config table must contain: class,x,y,z,plane,graphic."
|
"|"
|
||||||
"|The config table can optionally contain: facing.") {
|
"|The config table must contain: class,animstate."
|
||||||
|
"|" ){
|
||||||
LuaArg config;
|
LuaArg config;
|
||||||
LuaVar classname, classtab, mt;
|
LuaVar classname, classtab, mt, animstate;
|
||||||
LuaRet database;
|
LuaRet database;
|
||||||
LuaDefStack LS(L, config, classname, classtab, database, mt);
|
LuaDefStack LS(L, config, classname, classtab, database, mt, animstate);
|
||||||
LuaKeywordParser kp(LS, config);
|
LuaKeywordParser kp(LS, config);
|
||||||
|
|
||||||
// Get the class of the new tangible.
|
// Get the keyword arguments.
|
||||||
if (!kp.parse(classname, "class")) {
|
if (!kp.parse(classname, "class")) {
|
||||||
luaL_error(L, "You must specify a class for the tangible");
|
luaL_error(L, "You must specify a class for the tangible");
|
||||||
}
|
}
|
||||||
|
if (!kp.parse(animstate, "animstate")) {
|
||||||
|
luaL_error(L, "You must specify an animstate table");
|
||||||
|
}
|
||||||
|
kp.final_check_throw();
|
||||||
|
|
||||||
|
// Find the class.
|
||||||
eng::string err = LS.getclass(classtab, classname);
|
eng::string err = LS.getclass(classtab, classname);
|
||||||
if (err != "") {
|
if (err != "") {
|
||||||
luaL_error(L, "%s", err.c_str());
|
luaL_error(L, "%s", err.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the initial animation step.
|
// Calculate the initial animation state.
|
||||||
AnimStep initstep, blank;
|
AnimState state;
|
||||||
initstep.configure(kp, blank);
|
err = state.apply_lua(LS, animstate, true);
|
||||||
kp.final_check_throw();
|
if (err != "") {
|
||||||
if (!initstep.has_xyz()) {
|
luaL_error(L, "%s", err.c_str());
|
||||||
luaL_error(L, "You must specify (X,Y,Z) for new tangible");
|
|
||||||
}
|
}
|
||||||
if (!initstep.has_plane()) {
|
if (!state.contains("xyz") || !state.contains("plane")) {
|
||||||
luaL_error(L, "You must specify plane for new tangible");
|
luaL_error(L, "You must specify both xyz and plane in animstate");
|
||||||
}
|
}
|
||||||
if (!initstep.has_graphic()) {
|
err = state.add_defaults(nullptr);
|
||||||
luaL_error(L, "You must specify graphic for new tangible");
|
if (err != "") {
|
||||||
|
luaL_error(L, "%s", err.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: generate error if there's extra crap in the config table.
|
|
||||||
|
|
||||||
World *w = World::fetch_global_pointer(L);
|
World *w = World::fetch_global_pointer(L);
|
||||||
int64_t new_id = w->alloc_id_predictable();
|
int64_t new_id = w->alloc_id_predictable();
|
||||||
Tangible *tan = w->tangible_make(LS, database, new_id, "nowhere");
|
Tangible *tan = w->tangible_make(LS, database, new_id);
|
||||||
|
|
||||||
// Update the class of the new tangible.
|
// Update the class of the new tangible.
|
||||||
LS.getmetatable(mt, database);
|
LS.getmetatable(mt, database);
|
||||||
LS.rawset(mt, "__index", classtab);
|
LS.rawset(mt, "__index", classtab);
|
||||||
|
|
||||||
// Update the animation queue and planemap of the new tangible.
|
tan->anim_queue_.clear(state);
|
||||||
int64_t stepid = w->alloc_id_predictable();
|
|
||||||
tan->anim_queue_.add(stepid, initstep);
|
|
||||||
tan->update_plane_item();
|
|
||||||
|
|
||||||
return LS.result();
|
return LS.result();
|
||||||
}
|
}
|
||||||
@@ -259,34 +374,27 @@ LuaDefine(tangible_place, "",
|
|||||||
}
|
}
|
||||||
|
|
||||||
LuaDefine(tangible_near, "tan,radius,omit_nowhere,omit_self",
|
LuaDefine(tangible_near, "tan,radius,omit_nowhere,omit_self",
|
||||||
"|Scan near the specified tangible."
|
"|Deprecated. Use tangible.find instead.") {
|
||||||
"|If omit_nowhere is true, and the tangible is on the nowhere plane,"
|
|
||||||
"|then the scan returns empty. If omit_self is true, then the "
|
|
||||||
"|tangible passed in is omitted from the results.") {
|
|
||||||
LuaArg ltan, lradius, lomit_nowhere, lomit_self;
|
LuaArg ltan, lradius, lomit_nowhere, lomit_self;
|
||||||
LuaRet list;
|
LuaRet list;
|
||||||
LuaDefStack LS(L, ltan, lradius, lomit_nowhere, lomit_self, list);
|
LuaDefStack LS(L, ltan, lradius, lomit_nowhere, lomit_self, list);
|
||||||
World *w = World::fetch_global_pointer(L);
|
World *w = World::fetch_global_pointer(L);
|
||||||
Tangible *tan = w->tangible_get(LS, ltan, false);
|
Tangible *tan = w->tangible_get(LS, ltan, false);
|
||||||
const AnimStep &aqback = tan->anim_queue_.back();
|
|
||||||
|
|
||||||
PlaneScan scan;
|
PlaneScan scan;
|
||||||
scan.set_plane(aqback.plane());
|
scan.set_radius(LS.cknumber(lradius));
|
||||||
scan.set_bbox_given_center_radius(aqback.xyz(), LS.cknumber(lradius));
|
|
||||||
scan.set_shape(PlaneScan::SPHERE);
|
scan.set_shape(PlaneScan::SPHERE);
|
||||||
scan.set_sorted(true);
|
scan.set_sorted(true);
|
||||||
scan.set_near(tan->id(), !LS.ckboolean(lomit_self));
|
scan.set_near(tan->id(), !LS.ckboolean(lomit_self));
|
||||||
scan.set_omit_nowhere(LS.ckboolean(lomit_nowhere));
|
scan.set_omit_nowhere(LS.ckboolean(lomit_nowhere));
|
||||||
|
util::IdVector idv;
|
||||||
util::IdVector idv = w->plane_map_.scan(scan);
|
w->get_near(scan, &idv);
|
||||||
tangible_getall(LS, list, idv);
|
tangible_getall(LS, list, idv);
|
||||||
return LS.result();
|
return LS.result();
|
||||||
}
|
}
|
||||||
|
|
||||||
LuaDefine(tangible_scan, "plane,x,y,radius,omit_nowhere",
|
LuaDefine(tangible_scan, "plane,x,y,radius,omit_nowhere",
|
||||||
"|Scan the specified plane."
|
"|Deprecated. Use tangible.find instead.") {
|
||||||
"|If omit_nowhere is true, and the plane is 'nowhere', then"
|
|
||||||
"|the scan returns empty.") {
|
|
||||||
LuaArg lplane, lx, ly, lradius, lomit_nowhere;
|
LuaArg lplane, lx, ly, lradius, lomit_nowhere;
|
||||||
LuaRet list;
|
LuaRet list;
|
||||||
LuaDefStack LS(L, lplane, lx, ly, lradius, lomit_nowhere, list);
|
LuaDefStack LS(L, lplane, lx, ly, lradius, lomit_nowhere, list);
|
||||||
@@ -294,12 +402,13 @@ LuaDefine(tangible_scan, "plane,x,y,radius,omit_nowhere",
|
|||||||
|
|
||||||
PlaneScan scan;
|
PlaneScan scan;
|
||||||
scan.set_plane(LS.ckstring(lplane));
|
scan.set_plane(LS.ckstring(lplane));
|
||||||
scan.set_bbox_given_center_radius(util::XYZ(LS.cknumber(lx), LS.cknumber(ly), 0), LS.cknumber(lradius));
|
scan.set_center_and_radius(util::XYZ(LS.cknumber(lx), LS.cknumber(ly), 0), LS.cknumber(lradius));
|
||||||
scan.set_shape(PlaneScan::SPHERE);
|
scan.set_shape(PlaneScan::SPHERE);
|
||||||
scan.set_sorted(true);
|
scan.set_sorted(true);
|
||||||
scan.set_omit_nowhere(LS.ckboolean(lomit_nowhere));
|
scan.set_omit_nowhere(LS.ckboolean(lomit_nowhere));
|
||||||
|
|
||||||
util::IdVector idv = w->plane_map_.scan(scan);
|
util::IdVector idv;
|
||||||
|
w->get_near(scan, &idv);
|
||||||
tangible_getall(LS, list, idv);
|
tangible_getall(LS, list, idv);
|
||||||
return LS.result();
|
return LS.result();
|
||||||
}
|
}
|
||||||
@@ -369,21 +478,9 @@ LuaDefine(tangible_find, "config",
|
|||||||
scan.configure(kw);
|
scan.configure(kw);
|
||||||
kw.final_check_throw();
|
kw.final_check_throw();
|
||||||
|
|
||||||
// When the configure routine sees the 'near' flag, it stores the tangible
|
|
||||||
// ID, but not the center and plane, because doing so would require it to
|
|
||||||
// know about world models. We have to handle center and plane for 'near'
|
|
||||||
// separately.
|
|
||||||
World *w = World::fetch_global_pointer(L);
|
World *w = World::fetch_global_pointer(L);
|
||||||
int64_t near = scan.near();
|
util::IdVector idv;
|
||||||
if (near != 0) {
|
w->get_near(scan, &idv);
|
||||||
Tangible *t = w->tangible_get(near);
|
|
||||||
assert(t != nullptr); // Should never happen.
|
|
||||||
const AnimStep &aqback = t->anim_queue_.back();
|
|
||||||
scan.set_plane(aqback.plane());
|
|
||||||
scan.set_center(aqback.xyz());
|
|
||||||
}
|
|
||||||
// Do the scan.
|
|
||||||
util::IdVector idv = w->plane_map_.scan(scan);
|
|
||||||
tangible_getall(LS, result, idv);
|
tangible_getall(LS, result, idv);
|
||||||
return LS.result();
|
return LS.result();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,14 +77,14 @@ World::World(WorldType wt) {
|
|||||||
assign_seqno_ = 1;
|
assign_seqno_ = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Tangible::Tangible(World *w, int64_t id) : world_(w), anim_queue_(w->world_type_), id_player_pool_(&w->id_global_pool_) {
|
Tangible::Tangible(World *w, int64_t id) : world_(w), anim_queue_(), id_player_pool_(&w->id_global_pool_) {
|
||||||
plane_item_.set_id(id);
|
plane_item_.set_id(id);
|
||||||
plane_item_.track(&w->plane_map_);
|
plane_item_.track(&w->plane_map_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tangible::update_plane_item() {
|
void Tangible::update_plane_item() {
|
||||||
const AnimStep &aqback = anim_queue_.back();
|
AnimCoreState pos = anim_queue_.get_final_core_state();
|
||||||
plane_item_.set_pos(aqback.plane(), aqback.xyz().x, aqback.xyz().y, aqback.xyz().z);
|
plane_item_.set_pos(pos.plane, pos.xyz.x, pos.xyz.y, pos.xyz.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tangible::serialize(StreamBuffer *sb) {
|
void Tangible::serialize(StreamBuffer *sb) {
|
||||||
@@ -140,7 +140,7 @@ Tangible *World::tangible_get(const LuaCoreStack &LS, LuaSlot tab, bool allowdel
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Tangible *World::tangible_make(const LuaCoreStack &LS0, LuaSlot database, int64_t id, const eng::string &plane) {
|
Tangible *World::tangible_make(const LuaCoreStack &LS0, LuaSlot database, int64_t id) {
|
||||||
assert(id != 0);
|
assert(id != 0);
|
||||||
LuaVar metatab;
|
LuaVar metatab;
|
||||||
LuaExtStack LS(LS0.state(), metatab);
|
LuaExtStack LS(LS0.state(), metatab);
|
||||||
@@ -150,8 +150,10 @@ Tangible *World::tangible_make(const LuaCoreStack &LS0, LuaSlot database, int64_
|
|||||||
assert (t == nullptr);
|
assert (t == nullptr);
|
||||||
t.reset(new Tangible(this, id));
|
t.reset(new Tangible(this, id));
|
||||||
|
|
||||||
// Set up initial animation state.
|
// AnimQueue initializes itself to a valid default state.
|
||||||
t->anim_queue_.clear(plane);
|
AnimState state;
|
||||||
|
state.add_defaults(nullptr);
|
||||||
|
t->anim_queue_.clear(state);
|
||||||
t->update_plane_item();
|
t->update_plane_item();
|
||||||
|
|
||||||
// Fetch the tangible's Lua database and metatable.
|
// Fetch the tangible's Lua database and metatable.
|
||||||
@@ -165,10 +167,10 @@ Tangible *World::tangible_make(const LuaCoreStack &LS0, LuaSlot database, int64_
|
|||||||
return t.get();
|
return t.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
Tangible *World::tangible_make(int64_t id, const eng::string &plane) {
|
Tangible *World::tangible_make(int64_t id) {
|
||||||
LuaVar database;
|
LuaVar database;
|
||||||
LuaExtStack LS(state(), database);
|
LuaExtStack LS(state(), database);
|
||||||
return tangible_make(LS, database, id, plane);
|
return tangible_make(LS, database, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::tangible_delete(int64_t id) {
|
void World::tangible_delete(int64_t id) {
|
||||||
@@ -199,23 +201,33 @@ void World::tangible_delete(int64_t id) {
|
|||||||
tangibles_.erase(iter);
|
tangibles_.erase(iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
util::IdVector World::get_near(int64_t player_id, float radius, bool exclude_nowhere, bool omit_player, bool sorted) const {
|
void World::get_near(PlaneScan &scan, util::IdVector *into) const {
|
||||||
const Tangible *player = tangible_get(player_id);
|
uint32_t hash1 = eng::memhash();
|
||||||
|
into->clear();
|
||||||
|
// If 'near' is set, update the plane and center.
|
||||||
|
int64_t actor_id = scan.near();
|
||||||
|
if (actor_id != 0) {
|
||||||
|
const Tangible *player = tangible_get(actor_id);
|
||||||
if (player == nullptr) {
|
if (player == nullptr) {
|
||||||
return IdVector();
|
return;
|
||||||
}
|
}
|
||||||
|
const PlaneItem &pi = player->plane_item_;
|
||||||
|
scan.set_plane(pi.plane());
|
||||||
|
scan.set_center(util::XYZ(pi.x(), pi.y(), pi.z()));
|
||||||
|
}
|
||||||
|
plane_map_.scan(scan, into);
|
||||||
|
uint32_t hash2 = eng::memhash();
|
||||||
|
assert(hash1 == hash2);
|
||||||
|
}
|
||||||
|
|
||||||
// Find out where the player is.
|
void World::get_near(int64_t player_id, float radius, bool exclude_nowhere, bool omit_player, bool sorted, util::IdVector *into) const {
|
||||||
const AnimStep &aqback = player->anim_queue_.back();
|
|
||||||
|
|
||||||
PlaneScan scan;
|
PlaneScan scan;
|
||||||
scan.set_plane(aqback.plane());
|
scan.set_radius(radius);
|
||||||
scan.set_bbox_given_center_radius(aqback.xyz(), radius);
|
|
||||||
scan.set_shape(PlaneScan::SPHERE);
|
scan.set_shape(PlaneScan::SPHERE);
|
||||||
scan.set_sorted(sorted);
|
scan.set_sorted(sorted);
|
||||||
scan.set_omit_nowhere(exclude_nowhere);
|
scan.set_omit_nowhere(exclude_nowhere);
|
||||||
scan.set_near(player_id, !omit_player);
|
scan.set_near(player_id, !omit_player);
|
||||||
return plane_map_.scan(scan);
|
get_near(scan, into);
|
||||||
}
|
}
|
||||||
|
|
||||||
World::Redirects World::fetch_redirects() {
|
World::Redirects World::fetch_redirects() {
|
||||||
@@ -229,7 +241,7 @@ int64_t World::create_login_actor() {
|
|||||||
int64_t id = id_global_pool_.get_one();
|
int64_t id = id_global_pool_.get_one();
|
||||||
LuaVar database, classtab, mt;
|
LuaVar database, classtab, mt;
|
||||||
LuaExtStack LS(state(), database, classtab, mt);
|
LuaExtStack LS(state(), database, classtab, mt);
|
||||||
Tangible *tan = tangible_make(LS, database, id, "nowhere");
|
Tangible *tan = tangible_make(LS, database, id);
|
||||||
LS.makeclass(classtab, "login");
|
LS.makeclass(classtab, "login");
|
||||||
LS.getmetatable(mt, database);
|
LS.getmetatable(mt, database);
|
||||||
LS.rawset(mt, "__index", classtab);
|
LS.rawset(mt, "__index", classtab);
|
||||||
|
|||||||
@@ -3,9 +3,10 @@
|
|||||||
#include "serializelua.hpp"
|
#include "serializelua.hpp"
|
||||||
|
|
||||||
util::IdVector World::get_visible_union(int64_t actor_id, World *master) {
|
util::IdVector World::get_visible_union(int64_t actor_id, World *master) {
|
||||||
return util::sort_union_id_vectors(
|
util::IdVector v1, v2;
|
||||||
master->get_near(actor_id, RadiusVisibility, true, false, false),
|
master->get_near(actor_id, RadiusVisibility, true, false, false, &v1);
|
||||||
get_near(actor_id, RadiusVisibility, true, false, false));
|
get_near(actor_id, RadiusVisibility, true, false, false, &v2);
|
||||||
|
return util::sort_union_id_vectors(v1, v2);
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t World::patch_actor(StreamBuffer *sb, DebugCollector *dbc) {
|
int64_t World::patch_actor(StreamBuffer *sb, DebugCollector *dbc) {
|
||||||
@@ -14,7 +15,7 @@ int64_t World::patch_actor(StreamBuffer *sb, DebugCollector *dbc) {
|
|||||||
Tangible *s_actor = tangible_get(actor_id);
|
Tangible *s_actor = tangible_get(actor_id);
|
||||||
if (s_actor == nullptr) {
|
if (s_actor == nullptr) {
|
||||||
DebugLine(dbc) << "create new actor " << actor_id;
|
DebugLine(dbc) << "create new actor " << actor_id;
|
||||||
s_actor = tangible_make(actor_id, "");
|
s_actor = tangible_make(actor_id);
|
||||||
s_actor->id_player_pool_.deserialize(sb);
|
s_actor->id_player_pool_.deserialize(sb);
|
||||||
s_actor->anim_queue_.deserialize(sb);
|
s_actor->anim_queue_.deserialize(sb);
|
||||||
s_actor->print_buffer_.deserialize(sb);
|
s_actor->print_buffer_.deserialize(sb);
|
||||||
@@ -61,7 +62,7 @@ void World::patch_visible(StreamBuffer *sb, DebugCollector *dbc) {
|
|||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
int64_t id = sb->read_int64();
|
int64_t id = sb->read_int64();
|
||||||
DebugLine(dbc) << "patch_visible create tan " << id;
|
DebugLine(dbc) << "patch_visible create tan " << id;
|
||||||
Tangible *t = tangible_make(id, "");
|
Tangible *t = tangible_make(id);
|
||||||
t->anim_queue_.deserialize(sb);
|
t->anim_queue_.deserialize(sb);
|
||||||
t->update_plane_item();
|
t->update_plane_item();
|
||||||
}
|
}
|
||||||
@@ -162,7 +163,6 @@ void World::diff_visible(const util::IdVector &visible, World *master,
|
|||||||
s_tan = tangible_get(m_tan->id());
|
s_tan = tangible_get(m_tan->id());
|
||||||
assert(s_tan != nullptr);
|
assert(s_tan != nullptr);
|
||||||
}
|
}
|
||||||
s_tan->anim_queue_.update_version(m_tan->anim_queue_);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -172,8 +172,8 @@ void World::patch_luatabs(StreamBuffer *sb, DebugCollector *dbc) {
|
|||||||
int64_t actor_id = sb->read_int64();
|
int64_t actor_id = sb->read_int64();
|
||||||
util::HashValue closehash = sb->read_hashvalue();
|
util::HashValue closehash = sb->read_hashvalue();
|
||||||
int ncreate = sb->read_int32();
|
int ncreate = sb->read_int32();
|
||||||
util::IdVector closetans =
|
util::IdVector closetans;
|
||||||
get_near(actor_id, RadiusClose, true, false, true);
|
get_near(actor_id, RadiusClose, true, false, true, &closetans);
|
||||||
assert(closehash == util::hash_id_vector(closetans));
|
assert(closehash == util::hash_id_vector(closetans));
|
||||||
number_lua_tables(closetans);
|
number_lua_tables(closetans);
|
||||||
create_new_tables(ncreate);
|
create_new_tables(ncreate);
|
||||||
@@ -188,22 +188,23 @@ void World::diff_luatabs(int64_t actor_id, World *master, StreamBuffer *xsb) {
|
|||||||
StreamBuffer tsb;
|
StreamBuffer tsb;
|
||||||
|
|
||||||
// Calculate the set of close tangibles.
|
// Calculate the set of close tangibles.
|
||||||
util::IdVector closetans =
|
util::IdVector mclosetans, sclosetans;
|
||||||
master->get_near(actor_id, RadiusClose, true, false, true);
|
master->get_near(actor_id, RadiusClose, true, false, true, &mclosetans);
|
||||||
assert(get_near(actor_id, RadiusClose, true, false, true) == closetans);
|
get_near(actor_id, RadiusClose, true, false, true, &sclosetans);
|
||||||
util::HashValue closehash = util::hash_id_vector(closetans);
|
assert(mclosetans == sclosetans);
|
||||||
|
util::HashValue closehash = util::hash_id_vector(mclosetans);
|
||||||
|
|
||||||
// Number and pair tables in the synchronous and master model.
|
// Number and pair tables in the synchronous and master model.
|
||||||
number_lua_tables(closetans);
|
number_lua_tables(mclosetans);
|
||||||
pair_lua_tables(closetans, master->state());
|
pair_lua_tables(mclosetans, master->state());
|
||||||
int ncreate = number_remaining_tables(closetans, master->state());
|
int ncreate = number_remaining_tables(mclosetans, master->state());
|
||||||
create_new_tables(ncreate);
|
create_new_tables(ncreate);
|
||||||
|
|
||||||
// Difference transmit.
|
// Difference transmit.
|
||||||
tsb.write_int64(actor_id);
|
tsb.write_int64(actor_id);
|
||||||
tsb.write_hashvalue(closehash);
|
tsb.write_hashvalue(closehash);
|
||||||
tsb.write_int32(ncreate);
|
tsb.write_int32(ncreate);
|
||||||
diff_tangible_databases(closetans, master->state(), &tsb);
|
diff_tangible_databases(mclosetans, master->state(), &tsb);
|
||||||
diff_numbered_tables(master->state(), &tsb);
|
diff_numbered_tables(master->state(), &tsb);
|
||||||
|
|
||||||
// Forward to client, and apply to server-synchronous.
|
// Forward to client, and apply to server-synchronous.
|
||||||
@@ -257,8 +258,8 @@ void World::diff_tanclass(int64_t actor_id, World *master, StreamBuffer *xsb) {
|
|||||||
// Calculate the set of close tangibles.
|
// Calculate the set of close tangibles.
|
||||||
// TODO: we've already calculated this in an earlier function. This is
|
// TODO: we've already calculated this in an earlier function. This is
|
||||||
// wasteful.
|
// wasteful.
|
||||||
util::IdVector closetans =
|
util::IdVector closetans;
|
||||||
master->get_near(actor_id, RadiusClose, true, false, true);
|
master->get_near(actor_id, RadiusClose, true, false, true, &closetans);
|
||||||
|
|
||||||
tsb.write_int32(0);
|
tsb.write_int32(0);
|
||||||
int write_count_after = tsb.total_writes();
|
int write_count_after = tsb.total_writes();
|
||||||
|
|||||||
@@ -3,18 +3,37 @@
|
|||||||
#include "json.hpp"
|
#include "json.hpp"
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
void World::tangible_walkto(int64_t id, int64_t animid, float x, float y) {
|
|
||||||
|
void World::tangible_clear_anim_queue_to_empty(int64_t id) {
|
||||||
Tangible *t = tangible_get(id);
|
Tangible *t = tangible_get(id);
|
||||||
assert(animid != 0);
|
|
||||||
assert(t != nullptr);
|
assert(t != nullptr);
|
||||||
AnimStep step;
|
AnimState state;
|
||||||
step.set_action("walkto");
|
t->anim_queue_.clear(state);
|
||||||
step.set_x(x);
|
t->update_plane_item();
|
||||||
step.set_y(y);
|
|
||||||
t->anim_queue_.add(animid, step);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void World::tangible_clear_plane_and_xyz(int64_t id, const eng::string &plane, const util::DXYZ &xyz) {
|
||||||
|
Tangible *t = tangible_get(id);
|
||||||
|
assert(t != nullptr);
|
||||||
|
AnimState state;
|
||||||
|
state.set_string("plane", plane);
|
||||||
|
state.set_xyz("xyz", xyz);
|
||||||
|
state.set_persistent("plane");
|
||||||
|
state.set_persistent("xyz");
|
||||||
|
t->anim_queue_.clear(state);
|
||||||
|
t->update_plane_item();
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::tangible_walkto(int64_t id, float x, float y) {
|
||||||
|
Tangible *t = tangible_get(id);
|
||||||
|
assert(t != nullptr);
|
||||||
|
AnimState state = t->anim_queue_.get_final_persistent();
|
||||||
|
state.set_string("action", "walkto");
|
||||||
|
state.set_xyz("xyz", util::DXYZ(x,y,0.0));
|
||||||
|
t->anim_queue_.add(state);
|
||||||
|
}
|
||||||
|
|
||||||
eng::string World::tangible_anim_debug_string(int64_t id) const {
|
eng::string World::tangible_anim_debug_string(int64_t id) const {
|
||||||
const Tangible *t = tangible_get(id);
|
const Tangible *t = tangible_get(id);
|
||||||
if (t == 0) return "no such tangible";
|
if (t == 0) return "no such tangible";
|
||||||
@@ -40,10 +59,12 @@ eng::string World::tangible_ids_debug_string() const {
|
|||||||
|
|
||||||
eng::string World::tangibles_near_debug_string(int64_t actor, int64_t distance) {
|
eng::string World::tangibles_near_debug_string(int64_t actor, int64_t distance) {
|
||||||
eng::ostringstream result;
|
eng::ostringstream result;
|
||||||
for (int64_t id : get_near(actor, distance, true, false, true)) {
|
util::IdVector tans;
|
||||||
|
get_near(actor, distance, true, false, true, &tans);
|
||||||
|
for (int64_t id : tans) {
|
||||||
const Tangible *tan = tangible_get(id);
|
const Tangible *tan = tangible_get(id);
|
||||||
const AnimStep &aqback = tan->anim_queue_.back();
|
AnimState state = tan->anim_queue_.get_final_everything();
|
||||||
result << id << ": " << aqback.graphic() << " " << aqback.plane() << " " << aqback.xyz().debug_string() << std::endl;
|
result << id << ": " << state.debug_string() << std::endl;
|
||||||
}
|
}
|
||||||
return result.str();
|
return result.str();
|
||||||
}
|
}
|
||||||
@@ -267,53 +288,35 @@ LuaDefine(unittests_world1animdiff, "", "some unit tests") {
|
|||||||
util::IdVector ids = util::id_vector_create(123, 345);
|
util::IdVector ids = util::id_vector_create(123, 345);
|
||||||
|
|
||||||
// Create some tangibles, and add some animations.
|
// Create some tangibles, and add some animations.
|
||||||
m->tangible_make(123, "somewhere");
|
m->tangible_make(123);
|
||||||
m->tangible_make(345, "somewhere");
|
m->tangible_make(345);
|
||||||
m->tangible_walkto(123, 770, 3, 4);
|
m->tangible_clear_anim_queue_to_empty(123);
|
||||||
m->tangible_walkto(345, 771, 6, 2);
|
m->tangible_clear_anim_queue_to_empty(345);
|
||||||
|
m->tangible_walkto(123, 3, 4);
|
||||||
|
m->tangible_walkto(345, 6, 2);
|
||||||
LuaAssertStrEq(L, m->tangible_ids_debug_string(), "123,345");
|
LuaAssertStrEq(L, m->tangible_ids_debug_string(), "123,345");
|
||||||
LuaAssertStrEq(L, m->tangible_anim_debug_string(123),
|
LuaAssertStrEq(L, m->tangible_anim_debug_string(123), "[empty]; action:walkto xyz:3,4,0");
|
||||||
"id=0 action= plane=somewhere x=0 y=0 z=0 facing=0 graphic=; "
|
LuaAssertStrEq(L, m->tangible_anim_debug_string(345), "[empty]; action:walkto xyz:6,2,0");
|
||||||
"id=770 action=walkto x=3 y=4; ");
|
|
||||||
LuaAssertStrEq(L, m->tangible_anim_debug_string(345),
|
|
||||||
"id=0 action= plane=somewhere x=0 y=0 z=0 facing=0 graphic=; "
|
|
||||||
"id=771 action=walkto x=6 y=2; ");
|
|
||||||
|
|
||||||
// Now difference transmit all that to the client.
|
// Now difference transmit all that to the client.
|
||||||
ss->diff_visible(ids, m.get(), &sb);
|
ss->diff_visible(ids, m.get(), &sb);
|
||||||
cs->patch_visible(&sb, nullptr);
|
cs->patch_visible(&sb, nullptr);
|
||||||
LuaAssertStrEq(L, ss->tangible_ids_debug_string(), "123,345");
|
LuaAssertStrEq(L, ss->tangible_ids_debug_string(), "123,345");
|
||||||
LuaAssertStrEq(L, ss->tangible_anim_debug_string(123),
|
LuaAssertStrEq(L, ss->tangible_anim_debug_string(123), "[empty]; action:walkto xyz:3,4,0");
|
||||||
"id=0 action= plane=somewhere x=0 y=0 z=0 facing=0 graphic=; "
|
LuaAssertStrEq(L, ss->tangible_anim_debug_string(345), "[empty]; action:walkto xyz:6,2,0");
|
||||||
"id=770 action=walkto x=3 y=4; ");
|
|
||||||
LuaAssertStrEq(L, ss->tangible_anim_debug_string(345),
|
|
||||||
"id=0 action= plane=somewhere x=0 y=0 z=0 facing=0 graphic=; "
|
|
||||||
"id=771 action=walkto x=6 y=2; ");
|
|
||||||
LuaAssert(L, worlds_identical(ss, cs));
|
LuaAssert(L, worlds_identical(ss, cs));
|
||||||
|
|
||||||
// Now add some more animation records to the master.
|
// Now add some more animation records to the master.
|
||||||
m->tangible_walkto(123, 772, 7, 3);
|
m->tangible_walkto(123, 7, 3);
|
||||||
m->tangible_walkto(345, 773, 2, 5);
|
m->tangible_walkto(345, 2, 5);
|
||||||
LuaAssertStrEq(L, m->tangible_anim_debug_string(123),
|
LuaAssertStrEq(L, m->tangible_anim_debug_string(123), "[empty]; action:walkto xyz:3,4,0; action:walkto xyz:7,3,0");
|
||||||
"id=0 action= plane=somewhere x=0 y=0 z=0 facing=0 graphic=; "
|
LuaAssertStrEq(L, m->tangible_anim_debug_string(345), "[empty]; action:walkto xyz:6,2,0; action:walkto xyz:2,5,0");
|
||||||
"id=770 action=walkto x=3 y=4; "
|
|
||||||
"id=772 action=walkto x=7 y=3; ");
|
|
||||||
LuaAssertStrEq(L, m->tangible_anim_debug_string(345),
|
|
||||||
"id=0 action= plane=somewhere x=0 y=0 z=0 facing=0 graphic=; "
|
|
||||||
"id=771 action=walkto x=6 y=2; "
|
|
||||||
"id=773 action=walkto x=2 y=5; ");
|
|
||||||
|
|
||||||
// Now difference transmit all that to the client again.
|
// Now difference transmit all that to the client again.
|
||||||
ss->diff_visible(ids, m.get(), &sb);
|
ss->diff_visible(ids, m.get(), &sb);
|
||||||
cs->patch_visible(&sb, nullptr);
|
cs->patch_visible(&sb, nullptr);
|
||||||
LuaAssertStrEq(L, ss->tangible_anim_debug_string(123),
|
LuaAssertStrEq(L, ss->tangible_anim_debug_string(123), "[empty]; action:walkto xyz:3,4,0; action:walkto xyz:7,3,0");
|
||||||
"id=0 action= plane=somewhere x=0 y=0 z=0 facing=0 graphic=; "
|
LuaAssertStrEq(L, ss->tangible_anim_debug_string(345), "[empty]; action:walkto xyz:6,2,0; action:walkto xyz:2,5,0");
|
||||||
"id=770 action=walkto x=3 y=4; "
|
|
||||||
"id=772 action=walkto x=7 y=3; ");
|
|
||||||
LuaAssertStrEq(L, ss->tangible_anim_debug_string(345),
|
|
||||||
"id=0 action= plane=somewhere x=0 y=0 z=0 facing=0 graphic=; "
|
|
||||||
"id=771 action=walkto x=6 y=2; "
|
|
||||||
"id=773 action=walkto x=2 y=5; ");
|
|
||||||
LuaAssert(L, worlds_identical(ss, cs));
|
LuaAssert(L, worlds_identical(ss, cs));
|
||||||
|
|
||||||
// Delete tangible 345.
|
// Delete tangible 345.
|
||||||
@@ -337,7 +340,7 @@ LuaDefine(unittests_world2pairtab, "", "some unit tests") {
|
|||||||
|
|
||||||
// Create a master model containing some general tables, and
|
// Create a master model containing some general tables, and
|
||||||
// some specialty tables (not numberable).
|
// some specialty tables (not numberable).
|
||||||
m->tangible_make(123, "somewhere");
|
m->tangible_make(123);
|
||||||
m->tangible_set_string(123, "inventory.TID", "inventory");
|
m->tangible_set_string(123, "inventory.TID", "inventory");
|
||||||
m->tangible_set_string(123, "transactions.TID", "transactions");
|
m->tangible_set_string(123, "transactions.TID", "transactions");
|
||||||
m->tangible_set_string(123, "skills.TID", "skills");
|
m->tangible_set_string(123, "skills.TID", "skills");
|
||||||
@@ -348,7 +351,7 @@ LuaDefine(unittests_world2pairtab, "", "some unit tests") {
|
|||||||
|
|
||||||
// Now we're going to create a synchronous model that's similar to, but not
|
// Now we're going to create a synchronous model that's similar to, but not
|
||||||
// exactly the same as that master model.
|
// exactly the same as that master model.
|
||||||
ss->tangible_make(123, "somewhere");
|
ss->tangible_make(123);
|
||||||
ss->tangible_set_string(123, "inventory.TID", "inventory");
|
ss->tangible_set_string(123, "inventory.TID", "inventory");
|
||||||
ss->tangible_set_string(123, "skills.TID", "skills");
|
ss->tangible_set_string(123, "skills.TID", "skills");
|
||||||
ss->tangible_set_string(123, "skills.crap.TID", "skills.crap");
|
ss->tangible_set_string(123, "skills.crap.TID", "skills.crap");
|
||||||
@@ -384,12 +387,19 @@ LuaDefine(unittests_world3diffluatab, "", "some unit tests") {
|
|||||||
StreamBuffer sb;
|
StreamBuffer sb;
|
||||||
|
|
||||||
// Initialize all three models so that a tangible exists.
|
// Initialize all three models so that a tangible exists.
|
||||||
m->tangible_make(123, "somewhere");
|
m->tangible_make(123);
|
||||||
ss->tangible_make(123, "somewhere");
|
ss->tangible_make(123);
|
||||||
cs->tangible_make(123, "somewhere");
|
cs->tangible_make(123);
|
||||||
m->tangible_make(345, "somewhere");
|
m->tangible_make(345);
|
||||||
ss->tangible_make(345, "somewhere");
|
ss->tangible_make(345);
|
||||||
cs->tangible_make(345, "somewhere");
|
cs->tangible_make(345);
|
||||||
|
|
||||||
|
m->tangible_clear_plane_and_xyz(123, "earth", util::DXYZ(0,0,0));
|
||||||
|
ss->tangible_clear_plane_and_xyz(123, "earth", util::DXYZ(0,0,0));
|
||||||
|
cs->tangible_clear_plane_and_xyz(123, "earth", util::DXYZ(0,0,0));
|
||||||
|
m->tangible_clear_plane_and_xyz(345, "earth", util::DXYZ(0,0,0));
|
||||||
|
ss->tangible_clear_plane_and_xyz(345, "earth", util::DXYZ(0,0,0));
|
||||||
|
cs->tangible_clear_plane_and_xyz(345, "earth", util::DXYZ(0,0,0));
|
||||||
|
|
||||||
// Put some data into the master model.
|
// Put some data into the master model.
|
||||||
m->tangible_set_string(123, "bacon", "crispy");
|
m->tangible_set_string(123, "bacon", "crispy");
|
||||||
@@ -438,9 +448,9 @@ LuaDefine(unittests_world4difftanclass, "", "some unit tests") {
|
|||||||
StreamBuffer sb;
|
StreamBuffer sb;
|
||||||
|
|
||||||
// Initialize all three models so that a tangible exists.
|
// Initialize all three models so that a tangible exists.
|
||||||
m->tangible_make(123, "somewhere");
|
m->tangible_make(123);
|
||||||
ss->tangible_make(123, "somewhere");
|
ss->tangible_make(123);
|
||||||
cs->tangible_make(123, "somewhere");
|
cs->tangible_make(123);
|
||||||
|
|
||||||
// Change the lua class of the tangible.
|
// Change the lua class of the tangible.
|
||||||
m->tangible_set_class(123, "chicken");
|
m->tangible_set_class(123, "chicken");
|
||||||
|
|||||||
@@ -125,7 +125,15 @@ public:
|
|||||||
// The unsorted version returns the tangibles in an unpredictable order. If sorted
|
// The unsorted version returns the tangibles in an unpredictable order. If sorted
|
||||||
// is false, return them in an unpredictable order.
|
// is false, return them in an unpredictable order.
|
||||||
//
|
//
|
||||||
IdVector get_near(int64_t player_id, float radius, bool exclude_nowhere, bool omit_player, bool sorted) const;
|
void get_near(int64_t player_id, float radius, bool exclude_nowhere, bool omit_player, bool sorted, IdVector *into) const;
|
||||||
|
|
||||||
|
// get_near
|
||||||
|
//
|
||||||
|
// Get a list of tangibles in any arbitrary region. This differs from
|
||||||
|
// PlaneMap::scan in that if the scan specifies a 'near', then the plane
|
||||||
|
// and center of the scan are updated from the near tangible.
|
||||||
|
//
|
||||||
|
void get_near(PlaneScan &sc, IdVector *into) const;
|
||||||
|
|
||||||
// Make a tangible.
|
// Make a tangible.
|
||||||
//
|
//
|
||||||
@@ -133,8 +141,8 @@ public:
|
|||||||
// stack untouched. Returns a pointer to the C++ part of the tangible, and
|
// stack untouched. Returns a pointer to the C++ part of the tangible, and
|
||||||
// optionally stores the Lua part in a stack slot.
|
// optionally stores the Lua part in a stack slot.
|
||||||
//
|
//
|
||||||
Tangible *tangible_make(const LuaCoreStack &LS0, LuaSlot tan, int64_t id, const eng::string &plane);
|
Tangible *tangible_make(const LuaCoreStack &LS0, LuaSlot tan, int64_t id);
|
||||||
Tangible *tangible_make(int64_t id, const eng::string &plane);
|
Tangible *tangible_make(int64_t id);
|
||||||
|
|
||||||
// Get a pointer to the specified tangible.
|
// Get a pointer to the specified tangible.
|
||||||
//
|
//
|
||||||
@@ -362,9 +370,17 @@ public:
|
|||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Clear the animation queue and remove all persistent state.
|
||||||
|
//
|
||||||
|
void tangible_clear_anim_queue_to_empty(int64_t id);
|
||||||
|
|
||||||
|
// Clear the animation queue to a reasonable starting position.
|
||||||
|
//
|
||||||
|
void tangible_clear_plane_and_xyz(int64_t id, const eng::string &plane, const util::DXYZ &xyz);
|
||||||
|
|
||||||
// Add a 'walkto' animation to the specified tangible.
|
// Add a 'walkto' animation to the specified tangible.
|
||||||
//
|
//
|
||||||
void tangible_walkto(int64_t id, int64_t animid, float x, float y);
|
void tangible_walkto(int64_t id, float x, float y);
|
||||||
|
|
||||||
// Get the tangible's animation queue as a debug string.
|
// Get the tangible's animation queue as a debug string.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ function ug.the()
|
|||||||
|
|
||||||
lis=tangible.scan('globals',0,0,0,true)
|
lis=tangible.scan('globals',0,0,0,true)
|
||||||
if #lis==0 then
|
if #lis==0 then
|
||||||
local ugid=tangible.build{class='ug',x=0,y=0,z=0,plane='globals',graphic='box'}
|
local ugid=tangible.build{class='ug', animstate={xyz={0,0,0}, plane='globals'}}
|
||||||
print("The global table is "..tangible.id(ugid))
|
print("The global table is "..tangible.id(ugid))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user