From 3d5bcc32ea4ac19e8da7bcf4a59443f3a013ba6d Mon Sep 17 00:00:00 2001 From: Aaron Marks Date: Tue, 15 Nov 2005 11:41:17 +0000 Subject: Updated bindings, game state class and more (see ChangeLog). --- ChangeLog | 13 ++++++ TODO | 6 +-- scripts/init.rb | 59 +++++++++++++++++++++--- src/accounthandler.cpp | 6 +++ src/bindings.i | 9 +++- src/chathandler.cpp | 6 +++ src/client.cpp | 11 +++++ src/defines.h | 8 ++-- src/messagein.cpp | 2 +- src/state.cpp | 123 ++++++++++++++++++++++++++++++++++++++++++++----- src/state.h | 96 ++++++++++++++++++++++++++++++-------- 11 files changed, 293 insertions(+), 46 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6b78c18..147d9b5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2005-11-15 Aaron Marks + + * src/state.h, src/state.cpp: Updated world representation, added + various methods which provide easy access to the game world. + * src/defines.h: Added "private message" message. + * src/client.cpp, scripts/init.rb: Added experimental remote access + to Ruby's functionality. + +2005-11-14 Aaron Marks + + * src/bindings.i: Enabled "directors", allowing scripting language + to override virtual functions. + 2005-11-12 Aaron Marks * src/main.cpp: Added scripting with Ruby support diff --git a/TODO b/TODO index 7332d18..49658d6 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,5 @@ $Id$ - * Implement MessageHandler base for scripts which will call script's - receiveMessage. - * Enhance SWIG bindings to have support for items, objects etc. + * Provide interactive Ruby prompt. + * Better handling of std::string with SWIG + * Error handling for SWIG bindings (currently any problems will crash the server) diff --git a/scripts/init.rb b/scripts/init.rb index 25e8dbc..290598f 100644 --- a/scripts/init.rb +++ b/scripts/init.rb @@ -1,19 +1,66 @@ -print "Hello there, this is embedded into TMW!\n" +print "enter init.rb\n" class EquipHandler < Tmw::MessageHandler def initialize() super end - # this isn't possible -- does not override parent receiveMessage def receiveMessage(computer, message) + print "Message ID: ", message.getId(), "\n" item = message.readLong() slot = message.readByte() - print "Trying to equip ", item, " at ", slot, "\n" + print "Trying to equip ", item, " at ", slot.to_i(), "\n" + + result = Tmw::MessageOut.new() + result.writeShort(Tmw::SMSG_EQUIP_RESPONSE) + result.writeByte(Tmw::EQUIP_OK) + computer.send(result.getPacket()) + end +end + +# Override default equip message handler +Tmw::connectionHandler.registerHandler(Tmw::CMSG_EQUIP, EquipHandler.new()) + + +# Remote Ruby expression execution +class RubyHandler < Tmw::MessageHandler + def initialize() + super + print "Ruby message handler activated\n" + end + + def receiveMessage(computer, message) + src = message.readString() + print src, "\n"; + # doesn't work properly yet (need to have SWIG use std::string nicely) + #eval(src, TOPLEVEL_BINDING) + end +end + +Tmw::connectionHandler.registerHandler(0x800, RubyHandler.new()) + + +# simple enemy +class SimpleEnemy < Tmw::Being + def initialize() + super + end + + def update() + print "Updating!\n" end end -a = EquipHandler.new() -Tmw::connectionHandler.registerHandler(Tmw::CMSG_EQUIP, a) +# simple item +class SimpleItem < Tmw::Item + def initialize() + super + type = 100 + end + + def use() + print "USE THIS THING!!" + end +end -print "Done init.rb\n" +print "exit init.rb\n" diff --git a/src/accounthandler.cpp b/src/accounthandler.cpp index 2934afd..9127640 100644 --- a/src/accounthandler.cpp +++ b/src/accounthandler.cpp @@ -26,6 +26,7 @@ #include "storage.h" #include "account.h" #include "messageout.h" +#include "state.h" #include using tmwserv::Account; @@ -153,7 +154,12 @@ void AccountHandler::receiveMessage(NetComputer &computer, MessageIn &message) break; } + // set character computer.setCharacter(chars[charNum].get()); + + // place in world + //tmwserv::State &state = tmwserv::State::instance(); + //state.beings["start.tmx"].push_back(tmwserv::BeingPtr(computer.getCharacter())); result.writeByte(SELECT_OK); } diff --git a/src/bindings.i b/src/bindings.i index 7dbbfc9..d420be2 100644 --- a/src/bindings.i +++ b/src/bindings.i @@ -19,13 +19,14 @@ * * $Id$ */ -%module Tmw +%module(directors="1") Tmw %{ #include "defines.h" #include "messagehandler.h" #include "packet.h" #include "messagein.h" +#include "messageout.h" #include "netcomputer.h" #include "connectionhandler.h" #include "object.h" @@ -35,10 +36,16 @@ extern ConnectionHandler connectionHandler; %} +%feature("director") MessageHandler; +%feature("director") Object; +%feature("director") Item; +%feature("director") Being; + %include "defines.h" %include "messagehandler.h" %include "packet.h" %include "messagein.h" +%include "messageout.h" %include "netcomputer.h" %include "connectionhandler.h" %include "object.h" diff --git a/src/chathandler.cpp b/src/chathandler.cpp index 9884861..33f0eb3 100644 --- a/src/chathandler.cpp +++ b/src/chathandler.cpp @@ -48,6 +48,12 @@ void ChatHandler::receiveMessage(NetComputer &computer, MessageIn &message) } break; + case CMSG_PRIVMSG: + { + std::string user = message.readString(); + std::string text = message.readString(); + } break; + default: std::cout << "Invalid message type" << std::endl; break; diff --git a/src/client.cpp b/src/client.cpp index be2424b..e614255 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -55,6 +55,7 @@ int main(int argc, char *argv[]) printf ("5) Character selection\n"); printf ("6) Move character\n"); printf ("7) Equip item\n"); + printf ("9) Ruby expression\n"); printf ("Choose your option: "); std::cin >> answer; @@ -143,6 +144,16 @@ int main(int argc, char *argv[]) msg.writeByte(slot); } break; + case 9: + { + std::cout << "Expr: "; + std::cin >> line; + msg.writeShort(0x800); + msg.writeString(line); + + responseRequired = false; + } break; + default: continue; } diff --git a/src/defines.h b/src/defines.h index 32fb6cf..e49c80d 100644 --- a/src/defines.h +++ b/src/defines.h @@ -100,14 +100,16 @@ enum { SMSG_EQUIP_RESPONSE = 0x0302, // Chat - SMSG_CHAT = 0x0400, - SMSG_SYSTEM = 0x0401, + SMSG_SYSTEM = 0x0400, + SMSG_CHAT = 0x0401, SMSG_ANNOUNCEMENT = 0x0402, + SMSG_PRIVMSG = 0x0403, CMSG_SAY = 0x0410, CMSG_ANNOUNCE = 0x0411, + CMSG_PRIVMSG = 0x0412, // Other - SMSG_LOAD_MAP = 0x0500, + SMSG_LOAD_MAP = 0x0500, // NOTE: We will need more messages for in-game control (eg. moving a client to a new map/position etc.). Currently the protocol only caters for the bare basics. }; diff --git a/src/messagein.cpp b/src/messagein.cpp index f5eaefe..8434f30 100644 --- a/src/messagein.cpp +++ b/src/messagein.cpp @@ -116,7 +116,7 @@ std::string MessageIn::readString(int length) mPos += stringLength; readString = tmpString; - delete tmpString; + delete[] tmpString; } return readString; diff --git a/src/state.cpp b/src/state.cpp index a169e4c..919f181 100644 --- a/src/state.cpp +++ b/src/state.cpp @@ -24,6 +24,7 @@ #include "state.h" #include #include "messageout.h" +#include "utils/logger.h" namespace tmwserv { @@ -31,32 +32,32 @@ namespace tmwserv void State::update(ConnectionHandler &connectionHandler) { // update game state (update AI, etc.) - for (std::map::iterator i = beings.begin(); - i != beings.end(); + for (std::map::iterator i = maps.begin(); + i != maps.end(); i++) { - for (Beings::iterator b = i->second.begin(); - b != i->second.end(); + for (Beings::iterator b = i->second.beings.begin(); + b != i->second.beings.end(); b++) { b->get()->update(); } } // notify clients about changes in the game world (only on their maps) - // NOTE: This isn't finished ;) - for (std::map::iterator i = beings.begin(); - i != beings.end(); + // NOTE: Should only send differences in the game state. + for (std::map::iterator i = maps.begin(); + i != maps.end(); i++) { // - for (Beings::iterator b = i->second.begin(); - b != i->second.end(); + for (Beings::iterator b = i->second.beings.begin(); + b != i->second.beings.end(); b++) { // send info about other players - for (Beings::iterator b2 = i->second.begin(); - b2 != i->second.end(); + for (Beings::iterator b2 = i->second.beings.begin(); + b2 != i->second.beings.end(); b2++) { if (b != b2) { MessageOut msg; - msg.writeShort(SMSG_NEW_OBJECT); // of course this wont be send _all_ the time ;) + msg.writeShort(SMSG_NEW_BEING); // msg.writeLong(OBJECT_PLAYER); // type msg.writeLong((int)b2->get()); // id msg.writeLong(b2->get()->getX());// x @@ -67,7 +68,105 @@ void State::update(ConnectionHandler &connectionHandler) } } } +} + +void State::addBeing(Being *being, const std::string &map) { + if (!mapExists(map)) + return; + + if (!beingExists(being)) + maps[map].beings.push_back(tmwserv::BeingPtr(being)); +} + +void State::removeBeing(Being *being) { + for (std::map::iterator i = maps.begin(); + i != maps.end(); + i++) { + for (Beings::iterator b = i->second.beings.begin(); + b != i->second.beings.end(); + b++) { + if (b->get() == being) { + i->second.beings.erase(b); + return; + } + } + } +} + +bool State::mapExists(const std::string &map) { + std::map::iterator i = maps.find(map); + if (i == maps.end()) + return false; + return true; +} + +bool State::beingExists(Being *being) { + for (std::map::iterator i = maps.begin(); + i != maps.end(); + i++) { + for (Beings::iterator b = i->second.beings.begin(); + b != i->second.beings.end(); + b++) { + if (b->get() == being) + return true; + } + } + return false; +} + +void State::loadMap(const std::string &map) { + // load map + maps[map] = MapComposite(); +} +void State::addObject(Object *object, const std::string &map) { + // +} + +void State::removeObject(Object *object) { + // +} + +bool State::objectExists(Object *object) { + for (std::map::iterator i = maps.begin(); + i != maps.end(); + i++) { + for (std::vector::iterator b = i->second.objects.begin(); + b != i->second.objects.end(); + b++) { + if (*b == object) + return true; + } + } + return false; +} + +const std::string State::findPlayer(Being *being) { + for (std::map::iterator i = maps.begin(); + i != maps.end(); + i++) { + for (Beings::iterator b = i->second.beings.begin(); + b != i->second.beings.end(); + b++) { + if (b->get() == being) + return i->first; + } + } + return ""; +} + +const std::string State::findObject(Object *object) { + for (std::map::iterator i = maps.begin(); + i != maps.end(); + i++) { + for (std::vector::iterator b = i->second.objects.begin(); + b != i->second.objects.end(); + b++) { + if (*b == object) + return i->first; + } + } + return ""; } } // namespace tmwserv diff --git a/src/state.h b/src/state.h index 21bb756..4d1c9a3 100644 --- a/src/state.h +++ b/src/state.h @@ -36,7 +36,7 @@ namespace tmwserv /** * State class contains all information/procedures associated with the game - * state. + * world's state. */ class State : public utils::Singleton { @@ -45,36 +45,92 @@ class State : public utils::Singleton State() throw() { } ~State() throw() { } + /** + * Combined map/entity structure + */ + struct MapComposite { + /** + * Default constructor + */ + MapComposite() : map(NULL) { } + + /** + * Actual map + */ + Map *map; + + /** + * Beings located on the map + */ + Beings beings; + + /** + * Items located on the map + */ + std::vector objects; + }; + + /** + * List of maps + */ + std::map maps; + public: + /** - * Beings on map - * - * The key/value pair conforms to: - * First - map name - * Second - list of beings/players on the map - * - * NOTE: This could possibly be optimized by making first Being & second string. This will make many operations easier. + * Update game state (contains core server logic) */ - std::map beings; + void update(ConnectionHandler &); /** - * Items on map - * - * The key/value pair conforms to: - * First - map name - * Second - Item ID + * Add being to game world at specified map */ - std::map items; + void addBeing(Being *being, const std::string &map); /** - * Container for loaded maps. + * Remove being from game world */ - std::map maps; - + void removeBeing(Being *being); + /** - * Update game state (contains core server logic) + * Check to see if a map exists in game world */ - void update(ConnectionHandler &); + bool mapExists(const std::string &map); + + /** + * Check if being exists in game world already + */ + bool beingExists(Being *being); + + /** + * Load map into game world + */ + void loadMap(const std::string &map); + + /** + * Add object to the map + */ + void addObject(Object *object, const std::string &map); + + /** + * Remove an object from the map + */ + void removeObject(Object *object); + + /** + * Find out whether an object exists in the game world or not + */ + bool objectExists(Object *object); + + /** + * Find map player in world is on + */ + const std::string findPlayer(Being *being); + + /** + * Find map object in world is on + */ + const std::string findObject(Object *object); }; } // namespace tmwserv -- cgit