//////////////////////////////////////////////////////////////////////////////// // // enginewrapper.hpp // // This header file contains driver's interface to class DrivenEngine. // This is meant to be used across a DLL boundary. Since the DLL may have // been compiled by a different compiler than the driver, we use only simple // POD types and we only use C calling conventions. // // When calling a wrapper function, you must always pass in the wrapper as // the first parameter. // //////////////////////////////////////////////////////////////////////////////// #ifndef ENGINEWRAPPER_H #define ENGINEWRAPPER_H #include #include #define DRV_MAX_CHAN 256 #define DRV_MAX_LISTEN_PORTS 256 #define DRV_ERRMSG_SIZE 8192 #define DRV_SHORTSTRING_SIZE 65536 enum class AccessKind { INVALID, INVOKE_LUA_CALL, INVOKE_LUA_EXPR, INVOKE_FLUSH_PRINTS, INVOKE_TICK, INVOKE_LUA_SOURCE, PROBE_LUA_CALL, CONNECT_TO_SERVER, VALIDATE_LUA_EXPR, CHANNEL_PRINTS, SLASH_COMMAND, }; class DrivenEngine; class PlayLogfile; class ReplayLogfile; class World; struct EngineWrapper { char error[DRV_ERRMSG_SIZE]; char databuffer[DRV_SHORTSTRING_SIZE]; DrivenEngine *engine; World *world; PlayLogfile *wlog; ReplayLogfile *rlog; ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // // CONSTRUCTION // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // Of course, there's no constructor, since this is a C struct. // To initialize it, you use 'dlsym' or 'GetProcAddress' to get the // address of the function 'init_engine_wrapper'. Then, you call // the function init_engine_wrapper(&wrapper). ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // // GETTERS // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // Get a list of all the listening ports. The driver is expected // to fetch this set shortly after the event_init callback is invoked. // void (*get_listen_ports)(EngineWrapper *w, uint32_t *nports, const uint32_t **ports); // Get a list of all recently-opened channels that were created using // new_outgoing_channel. The driver should initiate outgoing // connections for these channels. // void (*get_new_outgoing)(EngineWrapper *w, uint32_t *nchanids, const uint32_t **chanids); // Get a string_view of the target of a channel. A target is a string like // "cert:whatever.com:80" or "nocert:whatever.com:80". // The first word indicate whether or not a valid SSL certificate // is required. The second word is the hostname. The third word is // the port number. The char string returned here is valid until // the channel is closed. // const char *(*get_target)(EngineWrapper *w, uint32_t chid); // Return true if the user has released all references to this channel. // In this case, the driver should initiate shutdown of the channel, // and the driver should eventually call notify_close. // bool (*get_channel_released)(EngineWrapper *w, uint32_t chid); // Get a pointer to the bytes in the outgoing buffer. The char pointer // returned here is naturally only valid until the buffer is changed. // This function is used for all channels, including sockets and stdio. // void (*get_outgoing)(EngineWrapper *w, uint32_t chid, uint32_t *len, const char **data); // Return true if the outgoing buffer is empty. // bool (*get_outgoing_empty)(EngineWrapper *w, uint32_t chid); // Get the clock. // // Get the current time. This is equal to the last value passed // in by invoke_event_update. // double (*get_clock)(EngineWrapper *w); // Check the 'have prints' flag. If true, then the engine // wants the driver to use CHANNEL_PRINTS to obtain prints. // bool (*get_have_prints)(EngineWrapper *w); // Check the 'rescan_lua_source' flag. If this flag is set, it means // that the engine wants the driver to rescan the lua source code. // When the driver sees this flag, it should rescan the source and call // set_lua_source_pack. // bool (*get_rescan_lua_source)(EngineWrapper *w); // If true, the engine is done. Stop the driver. // 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); // Do a scan to find tangibles near the specified player. // // Returns a count and a pointer to an array of tangible IDs. The returned // pointer is valid until the next call to get_tangibles_near. // void (*get_tangibles_near)(EngineWrapper *w, uint64_t tanid, double rx, double ry, double rz, uint32_t *count, int64_t **ids); // Get the animation queues for the specified tangibles. // // You must supply an array of tangible IDs. For each tangible, returns the // animation queue as a serialized string. The serialized format is // documented in header file animqueue.hpp. // // You must also supply a buffer for the string lengths, and a buffer for // the string pointers. Both buffers must have space for number of // tangibles specified in the call. // // The returned character pointers remain valid until the next call to // get_animation_queues. // void (*get_animation_queues)(EngineWrapper *w, uint32_t count, const int64_t *ids, uint32_t *lengths, const char **strings); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // // MUTATORS USED ONLY IN PLAY MODE // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // Create the driven engine. You must specify the type of engine you // want (typically 'lpxserver' or 'lpxclient'), and a filename for the // logfile. // void (*play_initialize)(EngineWrapper *w, const char *engtype, const char *logfn); // Clear the list of recently-opened channels. You are meant to fetch // new outgoing channels using get_new_outgoing, then you call // clear_new_outgoing after you've opened those channels. // void (*play_clear_new_outgoing)(EngineWrapper *w); // Notifies the channel that some bytes were transmitted. This causes those // bytes to be removed from the outgoing buffer. This function is used for // all channels, including sockets and stdio. // void (*play_sent_outgoing)(EngineWrapper *w, uint32_t chid, uint32_t nbytes); // Notifies the channel that some bytes were received. This causes those // bytes to be appended to the incoming buffer. This function is used for // all channels, including sockets and stdio. // void (*play_recv_incoming)(EngineWrapper *w, uint32_t chid, uint32_t len, const char *data); // Notify the channel that the connection was closed. This includes all // sorts of closes, including friendly termination, all the way to network // failure. Closing the channel doesn't delete it. The engine is // responsible for noticing that the channel closed and the engine must // delete it. Closing a channel prevents it from showing up in // 'list_channels'. // void (*play_notify_close)(EngineWrapper *w, uint32_t chid, uint32_t len, const char *data); // Notify the DrivenEngine that somebody connected to an incoming port. // This will cause the DrivenEngine to allocate a new channel and put the // new channel into the incoming channels queue. Returns the new channel // ID. The new incoming channel appears in the 'list_channels' list, // even before the engine pops the channel from the incoming channels queue. // uint32_t (*play_notify_accept)(EngineWrapper *w, uint32_t port); // Invoke the update event. // // The clock value must absolutely be monotonically increasing, // and it should roughly be equal to the number of seconds since // the program started. // void (*play_update)(EngineWrapper *w, double clock); // Send an invoke. // // This is the main pathway for blueprints, or the unreal C++ code, // to change the state of the world. // void (*play_access)(EngineWrapper *w, AccessKind kind, int64_t place, uint32_t datapklen, const char *datapk, uint32_t *retpklen, const char **retpk); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // // MUTATORS USED ONLY IN REPLAY MODE // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // Begin a replay. // // Opens the logfile and prepares to replay the log. // If an error occurs, the error buffer contains a message, // and the done flag is set to true. // void (*replay_initialize)(EngineWrapper *w, const char *logfn); // Execute a single step from the replay log. // // Calling this when 'done' is true is a no-op. // void (*replay_step)(EngineWrapper *w); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // // CALLBACKS USED ONLY IN REPLAY MODE // // The driver can store function pointers here. If it does so, these // functions will get called during replay_step operations. // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// void (*replay_cb_sent_outgoing)(void *vp, int chid, int nbytes, const char *data); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // // VOID POINTER USED IN REPLAY CALLBACKS // // The driver can store a void pointer here. This void pointer will get passed // to all the replay callbacks. // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// void *replay_cb_vp; ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // // FUNCTIONS THAT CAN BE USED AT ANY TIME // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // Hook dprintf // // The engine provides a function 'util::dprintf' to print debugging // messages. It does not use stderr or std::cerr, because in windows, those // go to the bit-bucket. // // This routine hooks dprintf to change where the output goes. Ideally, // the intent is to send the output somewhere easily accessible, like the // visual studio debug output log, or the unreal editor output log, or // something like that. Or, better yet, to all those places at once. // // The hook function will get passed one line of output at a time. The line // will only contain printable characters. The line will not contain a // newline - the newline is implied. // void (*hook_dprint)(void (*func)(const char *oneline, size_t size)); // Release: delete the engine object and close log files. // // Note that the wrapper must have already been initialized using // init_engine_wrapper. Otherwise, the 'release' function pointer would not // be initialized. If writing a logfile, this stores a 'clean exit' marker // in the logfile, indicating that the engine exited cleanly, as opposed to // crashing. // // If the wrapper is already in its clear state, this is a no-op. // void (*release)(EngineWrapper *w); }; #endif // ENGINEWRAPPER_HPP