Add Verse master-server functionality
authorNathan Letwory <nathan@letworyinteractive.com>
Thu, 12 Oct 2006 11:53:50 +0000 (11:53 +0000)
committerNathan Letwory <nathan@letworyinteractive.com>
Thu, 12 Oct 2006 11:53:50 +0000 (11:53 +0000)
* added two files from verse-master
* server list is available in outliner (new mode "Verse Servers")
* verse sessions are now also in new mode "Verse Sessions" in outliner
* fixed drawing of verse sessions and their nodes
* in user preferences System & OpenGL master-server ip setting (default master.uni-verse.org)
* in File>Verse entry "Get Servers" to get server list or
* RMB on "Available Verse Servers" in outliner to "Refresh" server list

Enjoy :)

17 files changed:
extern/verse/dist/Makefile
extern/verse/dist/SConstruct
extern/verse/dist/verse_ms.c [new file with mode: 0644]
extern/verse/dist/verse_ms.h [new file with mode: 0644]
extern/verse/make/msvc_7_0/libverse.vcproj
source/blender/blenkernel/BKE_verse.h
source/blender/blenkernel/intern/verse_session.c
source/blender/include/BIF_verse.h
source/blender/makesdna/DNA_ID.h
source/blender/makesdna/DNA_space_types.h
source/blender/makesdna/DNA_userdef_types.h
source/blender/src/header_info.c
source/blender/src/header_oops.c
source/blender/src/outliner.c
source/blender/src/space.c
source/blender/src/usiblender.c
source/blender/src/verse_common.c

index 34cc10603b425cab5c3e63341cdeb470932e7032..166fa1fd69cc59cb20a2237e32e63a012c417102 100644 (file)
@@ -30,7 +30,8 @@ LIBVERSE_SRC =  $(PROT_OUT) v_bignum.c v_cmd_buf.c v_connect.c \
                v_connection.c v_connection.h v_encryption.c \
                v_func_storage.c v_internal_verse.h v_man_pack_node.c \
                v_network.c v_network.h v_network_in_que.c v_network_out_que.c \
-               v_pack.c v_pack.h v_pack_method.c v_prime.c v_randgen.c v_util.c
+               v_pack.c v_pack.h v_pack_method.c v_prime.c v_randgen.c v_util.c \
+               verse_ms.c
 
 LIBVERSE_OBJ = $(patsubst %h,, $(LIBVERSE_SRC:%.c=%.o))
 
index d54f299c3f6d82ebb907dd237b02b599ee8891ba..b0b9ed3ef2f97270606e633b7d926d0502935932 100644 (file)
@@ -110,7 +110,8 @@ lib_source_files = (['v_cmd_buf.c',
                      'v_prime.c',
                      'v_randgen.c',
                      'v_util.c',
-                     'v_bignum.c'
+                     'v_bignum.c',
+                     'verse_ms.c'
                      ])
 lib_source_files.extend(cmd_gen_deps)
 
@@ -135,10 +136,11 @@ verselib_env.Append(CPPDEFINES = defines)
 verseserver_env = verse_env.Copy()
 verseserver_env.Append(CPPDEFINES = defines)
 verseserver_env.Append (LIBPATH = ['.'])
+verseserver_env.Append (LIBS= ['verse'])
 verseserver_env.Append (LIBS= platform_libs)
 
 verselib_env.BlenderLib(libname='verse', sources=lib_source_files, includes=["."], defines = defines, libtype=['core', 'intern'], priority = [5, 5])
-verseserver_env.BlenderProg(builddir="#"+root_build_dir+os.sep, progname='verse', sources=server_source_files, libs=['verse'],
+verseserver_env.BlenderProg(builddir="#"+root_build_dir+os.sep, progname='verse', sources=server_source_files, libs=[],
 libpath='#'+env['BF_BUILDDIR']+'/lib')
 
 
diff --git a/extern/verse/dist/verse_ms.c b/extern/verse/dist/verse_ms.c
new file mode 100644 (file)
index 0000000..84f3fdb
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+ * A helper library to send and parse master server pings. See the relevant
+ * header for details.
+ * 
+ * This code was written in 2006 by Emil Brink. It is released as public domain.
+*/
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "verse.h"
+#include "verse_ms.h"
+
+/* Build and send a MS:GET packet. */
+void verse_ms_get_send(const char *address, int fields, const char *tags)
+{
+       char    req[128];
+
+       strcpy(req, "MS:GET IP=");
+       if(fields & VERSE_MS_FIELD_DESCRIPTION)
+               strcat(req, "DE");
+       if(tags != NULL)
+       {
+               strcat(req, " TA=");
+               strcat(req, tags);
+       }
+       verse_send_ping(address, req);
+}
+
+/* Skip assign, i.e. "NAME=" string, at <msg>. Stores name into <put>, and then updates
+ * it. Returns NULL on parse error, in which case the <put> pointer is not advanced.
+*/
+static const char * skip_assign(char **put, const char *msg)
+{
+       if(isalpha(*msg))
+       {
+               char    *p = put != NULL ? *put : NULL;
+
+               if(p != NULL)
+                       *p++ = *msg;
+               msg++;
+               while(*msg && (isalnum(*msg) || *msg == '_'))
+               {
+                       if(p != NULL)
+                               *p++ = *msg;
+                       msg++;
+               }
+               if(*msg == '=')
+               {
+                       if(p != NULL)
+                               *p++ = '\0';
+                       if(put != NULL)
+                               *put = p;
+                       return msg + 1;
+               }
+       }
+       return NULL;
+}
+
+/** Skip value at <msg>, optionally storing de-quoted version through <put>,
+ * which is advanced. Returns NULL on parse error, without updating <put>.
+*/
+static const char * skip_value(char **put, const char *msg)
+{
+       char    *p = (put != NULL) ? *put : NULL;
+
+       if(*msg == '"')
+       {
+               msg++;
+               while(*msg != '\0' && *msg != '"')
+               {
+                       if(*msg == '\\')
+                       {
+                               if(msg[1] != '\0')
+                                       msg++;
+                               else
+                                       return NULL;
+                       }
+                       if(p != NULL)
+                               *p++ = *msg;
+                       msg++;
+               }
+               if(*msg == '"')
+               {
+                       if(p != NULL)
+                               *p++ = '\0';
+                       if(put != NULL)
+                               *put = p;
+                       msg++;
+                       if(*msg == '\0' || isspace(*msg))
+                               return msg;
+               }
+               return NULL;
+       }
+       while(*msg && !isspace(*msg))
+       {
+               if(*msg == '"')
+                       return NULL;
+               if(p != NULL)
+                       *p++ = *msg;
+               msg++;
+       }
+       if(p != NULL)
+               *p++ = '\0';
+       if(put != NULL)
+               *put = p;
+       return msg;
+}
+
+static const char * put_field(VMSField *field, char **put, const char *src)
+{
+       const char      *ptr;
+       char            *base = *put;
+
+       if((ptr = skip_assign(put, src)) != NULL && ptr - src > 1)
+       {
+               field->name = base;
+               src = ptr;
+               base = *put;
+               if((ptr = skip_value(put, src)) != NULL)
+               {
+                       field->value = base;
+                       return ptr;
+               }
+       }
+       return NULL;
+}
+
+static int cmp_fields(const void *a, const void *b)
+{
+       return strcmp(((const VMSField *) a)->name, ((const VMSField *) b)->name);
+}
+
+VMSServer ** verse_ms_list_parse(const char *msg)
+{
+       const char      *word[384];     /* Takes quite a lot of stack space. */
+       const char      *ptr;
+       char            *put;
+       size_t          num_word = 0, i, j, num_ip = 0, num_field, space = 0;
+       VMSServer               **desc, *next;
+       VMSField        *field;
+
+       if(strncmp(msg, "MS:LIST", 7) == 0)
+               msg += 7;
+       if(*msg != ' ')
+               return NULL;
+
+       /* Step one: split the string into words, at whitespace. Split is aware
+        * of quoting rules for value assignment, this is crucial. This split is
+        * non-invasive, meaning each "word" will be a suffix.
+       */
+       while(*msg)
+       {
+               while(isspace(*msg))
+                       msg++;
+               ptr = skip_assign(NULL, msg);
+               if(ptr != NULL)
+               {
+                       space += ptr - msg;
+                       word[num_word++] = msg;
+                       msg = ptr;
+                       ptr = skip_value(NULL, msg);
+                       if(ptr == NULL)
+                       {
+                               fprintf(stderr, "Parse error\n");
+                               return NULL;
+                       }
+                       space += ptr - msg + 1;
+                       msg = ptr;
+               }
+               else if(*msg != '\0')
+               {
+                       fprintf(stderr, "Parse error\n");
+                       return NULL;
+               }
+       }
+       /* Now, count how many words begin with "IP=". */
+       for(i = 0; i < num_word; i++)
+       {
+               if(strncmp(word[i], "IP=", 3) == 0)
+                       num_ip++;
+       }
+/*     printf("found %u IPs, %u bytes\n", num_ip, space);
+       printf("%u IP and %u words -> %u fields total\n", num_ip, num_word, num_word - num_ip);
+*/     num_field = num_word - num_ip;
+       /* Allocate the descriptions. */
+/*     printf("allocating %u bytes\n", (num_ip + 1) * (sizeof *desc) + num_ip * sizeof **desc + num_field * sizeof (VMSField) + space);
+       printf(" %u for pointers, %u for structs, %u for fields, %u string\n",
+              (num_ip + 1) * (sizeof *desc), num_ip * sizeof **desc, num_field * sizeof (VMSField), space);
+*/     desc = malloc((num_ip + 1) * (sizeof *desc) + num_ip * sizeof **desc + num_field * sizeof (VMSField) + space);
+       next = (VMSServer *) (desc + (num_ip + 1));
+/*     printf("desc store at %u\n", (char *) next - (char *) desc);*/
+       field = (VMSField *) (next + num_ip);
+/*     printf("field store at %u\n", (char *) field - (char *) desc);*/
+       put  = (char *) (field + num_field);
+/*     printf("string store at %u\n", put - (char *) desc);*/
+       for(i = j = 0; i < num_word;)
+       {
+               if(strncmp(word[i], "IP=", 3) == 0)
+               {
+                       desc[j] = next;
+                       next->ip = put;
+                       ptr = skip_value(&put, word[i] + 3);
+                       next->num_fields = 0;
+                       next->field = field;
+                       for(i++; i < num_word && strncmp(word[i], "IP=", 3) != 0; i++, next->num_fields++, field++)
+                               put_field(&next->field[next->num_fields], &put, word[i]);
+                       if(next->num_fields > 0)        /* Sort the fields, for binary search later. */
+                               qsort(next->field, next->num_fields, sizeof *next->field, cmp_fields);
+                       j++;
+                       next++;
+               }
+               else
+                       i++;
+       }
+       desc[j] = NULL;
+       return desc;
+}
+
+/* A binary search, exploiting that the fields are sorted. */
+static const VMSField * field_find(const VMSServer *ms, const char *name)
+{
+       int     lo, hi, mid, rel;
+
+       if(ms == NULL || name == NULL)
+               return NULL;
+       lo = 0;
+       hi = ms->num_fields;
+       while(lo <= hi)
+       {
+               mid = (lo + hi) / 2;
+               rel = strcmp(name, ms->field[mid].name);
+               if(rel == 0)
+                       return &ms->field[mid];
+               if(rel < 0)
+                       hi = mid - 1;
+               else
+                       lo = mid + 1;
+       }
+       return NULL;
+}
+
+int verse_ms_field_exists(const VMSServer *ms, const char *name)
+{
+       if(ms == NULL || name == NULL)
+               return 0;
+       return field_find(ms, name) != NULL;
+}
+
+const char * verse_ms_field_value(const VMSServer *ms, const char *name)
+{
+       const VMSField  *f;
+
+       if((f = field_find(ms, name)) != NULL)
+               return f->value;
+       return NULL;
+}
+
+#if defined VERSE_MS_STANDALONE
+
+int main(void)
+{
+       VMSServer       **servers = verse_ms_list_parse("MS:LIST IP=127.0.0.1:4951 DE=\"A test server, mainly for Eskil\" COOL=yes BACKUP=daily LANG=sv_SE "
+                                               "IP=130.237.221.74 DE=\"Test server on a puny laptop\" COOL=yes DORKY=no OPEN=absolutely "
+                                               "IP=127.0.0.1:5151 DE=\"This is a back slash: '\\\\', cool huh?\" "
+                                               "IP=127.0.0.1:6676 DE=\"a quote looks like this: \\\"\"  IP=127.0.0.1:1122 ");
+
+       if(servers != NULL)
+       {
+               int     i, j;
+
+               printf("Server info:\n");
+               for(i = 0; servers[i] != NULL; i++)
+               {
+                       printf("%u: IP=%s\n", i, servers[i]->ip);
+                       for(j = 0; j < servers[i]->num_fields; j++)
+                               printf(" %s='%s'\n", servers[i]->field[j].name, servers[i]->field[j].value);
+               }
+               free(servers);
+       }
+       return EXIT_SUCCESS;
+}
+
+#endif         /* VERSE_MS_STANDALONE */
diff --git a/extern/verse/dist/verse_ms.h b/extern/verse/dist/verse_ms.h
new file mode 100644 (file)
index 0000000..5a27d3f
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * This is Verse Master Server, a small help library to aid application developers
+ * make their applications interact with a Verse master server.
+ * 
+ * There are two steps to the process:
+ * 
+ * 1) Send a MS:GET request to a master server. This is done by the verse_ms_get_send()
+ *    function, which calls verse_send_ping() internally.
+ * 
+ * 2) Parse any returned MS:LIST packets. This is a two-step process. The application
+ *    still owns the ping callback, and will need to check for received pings that
+ *    start with MS:LIST, and call the verse_ms_list_parse() function to parse those.
+ * 
+ * A successfully parsed MS:LIST packet will result in an array of VMSServer pointers
+ * being returned. Each VMSServer instance describes one server. Use the provided
+ * functions to query each server structure.
+ * 
+ * The application should call free() on the returned vector, whenever it is done with
+ * the data (perhaps after copying it into application-defined data structures).
+ * 
+ * For a lot more detail about the Verse master server protocol, please see
+ * the spec at <http://verse.blender.org/cms/Master_Server__v2.775.0.html>.
+ * 
+ * This code was written in 2006 by Emil Brink. It is released as public domain.
+ * 
+*/
+
+#define        VERSE_MS_VERSION        "1.0"
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+       const char      *name;          /* Field name. Upper-case. */
+       const char      *value;         /* Field value. Fully parsed, might contain spaces. */
+} VMSField;
+
+typedef struct {
+       const char      *ip;            /* IP address of server, in dotted decimal:port. */
+       unsigned int    num_fields;     /* Number of fields of extra info. */
+       VMSField        *field;         /* Vector of fields, or NULL if none. */
+} VMSServer;
+
+/* Formats and sends a MS:GET ping packet to the master server. The <fields> argument
+ * should be a combination of VERSE_MS_FIELD_ mask values. If <tags> is set, it should
+ * be a comma-separated set of include/exclude tags, like "a,b,-c,d,-e".
+*/
+#define        VERSE_MS_FIELD_DESCRIPTION      (1 << 0)
+extern void            verse_ms_get_send(const char *address, int fields, const char *tags);
+
+/* Parses a master server response. This will be a string of the form "MS:LIST IP=blah ...",
+ * which is split into one struct per IP, and any additional fields parsed (unquoted etc).
+ * Returns an array of VMSServer pointers, which is NULL-terminated. Returns NULL if there
+ * was a parse error somewhere in the string, no partial success is possible.
+*/
+extern VMSServer **    verse_ms_list_parse(const char *list);
+
+/* This is the only standard field name, currently. */
+#define        VERSE_MS_FIELD_DESCRIPTION_NAME "DE"    /* Human-readable server description. */
+
+/* Checks wether the given server has a field with the given name. */
+extern int             verse_ms_field_exists(const VMSServer *ms, const char *name);
+
+/* Returns the value for the named field in the given server, if present.
+ * If not, NULL is returned.
+*/
+extern const char *    verse_ms_field_value(const VMSServer *ms, const char *name);
+
+#if defined __cplusplus
+}
+#endif
index ecf6208ac3dce54233c3554d682793b2c5c14410..1c9bfbfce33cf13395376c856971108b860ab3cc 100644 (file)
@@ -229,6 +229,9 @@ ECHO Done
                        <File
                                RelativePath="..\..\dist\v_util.c">
                        </File>
+                       <File
+                               RelativePath="..\..\dist\verse_ms.c">
+                       </File>
                </Filter>
                <Filter
                        Name="Header Files"
@@ -267,6 +270,9 @@ ECHO Done
                                RelativePath="..\..\dist\v_util.h">
                        </File>
                </Filter>
+                       <File
+                               RelativePath="..\..\dist\verse_ms.h">
+                       </File>
        </Files>
        <Globals>
        </Globals>
index 00a6bdd4e60898ee28ac708d820cfb1f64c04dce..932a11f2f948a7c17d19542f733a38abfacdf225 100644 (file)
@@ -34,6 +34,7 @@
 #include "BLI_dynamiclist.h"
 
 #include "verse.h"
+#include "verse_ms.h"
 
 struct VNode;
 
@@ -322,6 +323,13 @@ typedef struct VNode {
        void (*post_node_name_set)(struct VNode *vnode);
 } VNode;
 
+typedef struct VerseServer {
+       struct VerseServer *next, *prev;
+       char *name; /* human-readable server name */
+       char *ip;   /* string containing IP/domain name of verse server and number of port */
+       short flag; /* flag: VERSE_CONNECTING, VERSE_CONNECTED */
+} VerseServer;
+
 /*
  * Verse Session: verse client can be connected to several verse servers
  * it is neccessary to store some information about each session
@@ -438,6 +446,7 @@ struct VerseSession *current_verse_session(void);
 struct VerseSession *create_verse_session(const char *name, const char *pass, const char *address, uint8 *expected_key);
 void free_verse_session(struct VerseSession *session);
 void b_verse_update(void);
+void b_vers_ms_get(void);
 void b_verse_connect(char *address);
 void end_verse_session(struct VerseSession *session, char free);
 void end_all_verse_sessions(void);
index e6f16a93239eb6f4ffcb19ff087171505262de05..d4b4a0b0fa7430cb43ddc10d19306cbdbe88bba9 100644 (file)
@@ -34,6 +34,7 @@
 #include "DNA_mesh_types.h"    /* temp */
 #include "DNA_listBase.h"
 #include "DNA_screen_types.h"
+#include "DNA_userdef_types.h"
 
 #include "BLI_dynamiclist.h"
 #include "BLI_blenlib.h"
 #include "BKE_global.h"        
 #include "BKE_verse.h"
 
-#include "verse.h"
-
 struct ListBase session_list={NULL, NULL};
+struct ListBase server_list={NULL, NULL};
+
+static cb_ping_registered = 0;
 
 /* list of static function prototypes */
 static void cb_connect_terminate(const char *address, const char *bye);
 static void cb_connect_accept(void *user_data, uint32 avatar, void *address, void *connection, const uint8 *host_id);
 static void set_all_callbacks(void);
 static void free_verse_session_data(struct VerseSession *session);
+static void add_verse_server(VMSServer *server);
+static void check_connection_state(struct VerseServer *server);
+
+static void check_connection_state(struct VerseServer *server)
+{
+       struct VerseSession *session;
+       session = session_list.first;
+       while(session) {
+               if(strcmp(server->ip,session->address)==0) {
+                       server->flag = session->flag;
+                       return;
+               }
+               session = session->next;
+       }
+}
+/*
+ * add verse server to server_list. Prevents duplicate
+ * entries
+ */
+static void add_verse_server(VMSServer *server)
+{
+       struct VerseServer *iter, *niter;
+       VerseServer *newserver;
+       const char *name = verse_ms_field_value(server, "DE");
+       iter = server_list.first;
+
+       while(iter) {
+               niter = iter->next;
+               if(strcmp(iter->ip, server->ip)==0) {
+                       return;
+               }
+               iter = niter;
+       }
+
+       newserver = (VerseServer *)MEM_mallocN(sizeof(VerseServer), "VerseServer");
+       newserver->ip = (char *)MEM_mallocN(sizeof(char)*(strlen(server->ip)+1), "VerseServer ip");
+       strcpy(newserver->ip, server->ip);
+
+       if(name) {
+               newserver->name = (char *)MEM_mallocN(sizeof(char)*(strlen(name)+strlen(newserver->ip)+4), "VerseServer name");
+               strcpy(newserver->name, name);
+               strcat(newserver->name, " (");
+               strcat(newserver->name, newserver->ip);
+               strcat(newserver->name, ")");
+       }
+
+       newserver->flag = 0;
+       check_connection_state(newserver);
+
+       printf("Adding new verse server: %s at %s\n", newserver->name, newserver->ip);
+
+       BLI_addtail(&server_list, newserver);
+       post_server_add();
+}
+
+/*
+ * callback function for ping
+ */
+static void cb_ping(void *user, const char *address, const char *message)
+{
+       VMSServer       **servers = verse_ms_list_parse(message);
+       if(servers != NULL)
+       {
+               int     i, j;
+
+               for(i = 0; servers[i] != NULL; i++)
+               {
+                       add_verse_server(servers[i]);
+               }
+               free(servers);
+       }
+}
 
 /*
  * callback function for connection terminated
@@ -83,6 +157,7 @@ static void cb_connect_accept(
                const uint8 *host_id)
 {
        struct VerseSession *session = (VerseSession*)current_verse_session();
+       struct VerseServer *server = server_list.first;
        uint32 i, mask=0;
 
        if(!session) return;
@@ -90,6 +165,14 @@ static void cb_connect_accept(
        session->flag |= VERSE_CONNECTED;
        session->flag &= ~VERSE_CONNECTING;
 
+       while(server) {
+               if(strcmp(session->address, server->ip)==0) {
+                       server->flag |= VERSE_CONNECTED;
+                       server->flag &= ~VERSE_CONNECTING;
+               }
+               server = server->next;
+       }
+
        printf("\tBlender was connected to verse server: %s\n", (char*)address);
        printf("\tVerseSession->counter: %d\n", session->counter);
 
@@ -111,6 +194,7 @@ void set_verse_session_callbacks(void)
        verse_callback_set(verse_send_connect_accept, cb_connect_accept, NULL);
        /* connection was terminated */
        verse_callback_set(verse_send_connect_terminate, cb_connect_terminate, NULL);
+
 }
 
 /*
@@ -151,6 +235,9 @@ void b_verse_update(void)
                }
                session = next_session;
        }
+       if(cb_ping_registered>0) {
+                       verse_callback_update(10);
+       }
 }
 
 /*
@@ -298,8 +385,27 @@ void end_verse_session(VerseSession *session, char free)
        if(free) free_verse_session(session);
 }
 
+void free_all_servers(void)
+{
+       VerseServer *server, *nextserver;
+
+       server = server_list.first;
+
+       while(server) {
+                       nextserver = server->next;
+                       BLI_remlink(&server_list, server);
+                       MEM_freeN(server->name);
+                       MEM_freeN(server->ip);
+                       MEM_freeN(server);
+                       server = nextserver;
+       }
+       
+       BLI_freelistN(&server_list);
+}
+
 /*
  * end connection to all verse hosts (servers) ... free all VerseSessions
+ * free all VerseServers
  */
 void end_all_verse_sessions(void)
 {
@@ -314,6 +420,25 @@ void end_all_verse_sessions(void)
        }
 
        BLI_freelistN(&session_list);
+
+       free_all_servers();
+}
+
+/*
+ * do a get from ms
+ */
+void b_verse_ms_get(void)
+{
+               if(cb_ping_registered==0) {
+                               /* handle ping messages (for master server) */
+                               verse_callback_set(verse_send_ping, cb_ping, NULL);
+                               add_screenhandler(G.curscreen, SCREEN_HANDLER_VERSE, 1);
+                               cb_ping_registered++;
+               }
+               free_all_servers();
+
+               verse_ms_get_send(U.versemaster, VERSE_MS_FIELD_DESCRIPTION, NULL);
+               verse_callback_update(10);
 }
 
 /*
index 7dada3f3986bde12ff45ba733723910aeda8ed20..74eed5e6b57c8e1d6f0b2e21c0ac9aa79dd8c680 100644 (file)
@@ -120,6 +120,7 @@ void post_node_name_set(struct VNode *vnode);
 void post_connect_accept(struct VerseSession *session);
 void post_connect_terminated(struct VerseSession *session);
 void post_connect_update(struct VerseSession *session);
+void post_server_add(void);
 
 /* verse_image.c */
 
index 847f71231501d09ba7ae137352c702c3a8ed1001..d11b6ad567ec115f84378fb42a0d56435303b053 100644 (file)
@@ -143,6 +143,8 @@ typedef struct Library {
 /*#ifdef WITH_VERSE*/
 #define ID_VS          MAKE_ID2('V', 'S')      /* fake id for VerseSession, needed for outliner */
 #define ID_VN          MAKE_ID2('V', 'N')      /* fake id for VerseNode, needed for outliner */
+#define ID_MS          MAKE_ID2('M', 'S')  /* fake id for VerseServer root entry, needed for outliner */
+#define ID_SS          MAKE_ID2('S', 'S')  /* fake id for VerseServer entry, needed for ountliner */
 /*#endif*/
 
 
index 6f21eb86f56d25c87ca61f620c88e54524db8e0c..d5f50529ca90d446de0ce9732f5ad789f4451469 100644 (file)
@@ -527,6 +527,8 @@ typedef struct SpaceImaSel {
 #define SO_SAME_TYPE   5
 #define SO_GROUPS              6
 #define SO_LIBRARIES   7
+#define SO_VERSE_SESSION       8
+#define SO_VERSE_MS            9
 
 /* SpaceOops->storeflag */
 #define SO_TREESTORE_CLEANUP   1
index 6a73f9a6674891453dcda49930af4dce3b7afe88..936321dd31208473e677d395ee9b822c0f19a3b8 100644 (file)
@@ -172,6 +172,7 @@ typedef struct UserDef {
        short obcenter_dia;
        short rvisize;          /* rotating view icon size */
        short rvibright;        /* rotating view icon brightness */
+       char versemaster[160];
        short pad1;
 } UserDef;
 
index 6ab3f8fee69a48f1b9f8b2ae0e7cbc8704096795..f96bd8b7b2be90de03fcfa05d3cdf0378bbd60df 100644 (file)
@@ -773,6 +773,10 @@ static void do_verse_filemenu(void *arg, int event)
                        printf("Disconnecting all sessions!\n");
                        end_all_verse_sessions();
                        break;
+        case 4:
+            printf("sending get to master server\n");
+            b_verse_ms_get();
+            break;
        }
 }
 
@@ -799,6 +803,7 @@ static uiBlock *verse_filemenu(void *unusedargs)
                }
                
        }
+       uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Get Servers", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
 
        uiBlockSetDirection(block, UI_RIGHT);
        uiTextBoundsBlock(block, 60);
index 98dbced9dbd64ced1654c2ae6437928a1b49df99..c4ebda76eae1a1c7ad7118fd842792198dd66199 100644 (file)
@@ -477,10 +477,18 @@ void oops_buttons(void)
        } 
 #endif
        else {
-               if(G.main->library.first)
+               if(G.main->library.first) 
+#ifdef WITH_VERSE
+                       uiDefButS(block, MENU, B_REDR, "Outliner Display%t|Verse Servers %x9|Verse Sessions %x8|Libraries %x7|All Scenes %x0|Current Scene %x1|Visible Layers %x2|Groups %x6|Same Types %x5|Selected %x3|Active %x4",    xco, 0, 100, 20,  &soops->outlinevis, 0, 0, 0, 0, "");
+#else
                        uiDefButS(block, MENU, B_REDR, "Outliner Display%t|Libraries %x7|All Scenes %x0|Current Scene %x1|Visible Layers %x2|Groups %x6|Same Types %x5|Selected %x3|Active %x4",         xco, 0, 100, 20,  &soops->outlinevis, 0, 0, 0, 0, "");
+#endif /* WITH_VERSE */
                else
+#ifdef WITH_VERSE
+                       uiDefButS(block, MENU, B_REDR, "Outliner Display%t|Verse Servers %x9|Verse Sessions %x8|All Scenes %x0|Current Scene %x1|Visible Layers %x2|Groups %x6|Same Types %x5|Selected %x3|Active %x4",  xco, 0, 100, 20,  &soops->outlinevis, 0, 0, 0, 0, "");
+#else
                        uiDefButS(block, MENU, B_REDR, "Outliner Display%t|All Scenes %x0|Current Scene %x1|Visible Layers %x2|Groups %x6|Same Types %x5|Selected %x3|Active %x4",       xco, 0, 100, 20,  &soops->outlinevis, 0, 0, 0, 0, "");
+#endif /* WITH_VERSE */
        }
        
        /* always do as last */
index f9e9e06e99f80a1cacfb5b917bf45dbff667230a..40fb31fcbf7abefa3ae777ba999399c2b56bddc6 100644 (file)
 
 #ifdef WITH_VERSE
 extern ListBase session_list;
+extern ListBase server_list;
 #endif
 
 /* ******************** PERSISTANT DATA ***************** */
@@ -724,6 +725,16 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
                te->directdata = (void*)session;
                te->idcode = ID_VS;
        }
+       else if(type==ID_MS) {
+               te->name = "Available Verse Servers";
+               te->idcode = ID_MS;
+       }
+       else if(type==ID_SS) {
+               struct VerseServer *server = (VerseServer *)idv;
+               te->name = server->name;
+               te->directdata = (void *)server;
+               te->idcode = ID_SS;
+       }
        else if(type==ID_VN) {
                struct VNode *vnode = (VNode*)idv;
                te->name = vnode->name;
@@ -888,31 +899,44 @@ static void outliner_build_tree(SpaceOops *soops)
                }
                outliner_make_hierarchy(soops, &soops->tree);
        }
-       else {
-               ten= outliner_add_element(soops, &soops->tree, OBACT, NULL, 0, 0);
-               if(ten) ten->directdata= BASACT;
-       }
-
 #ifdef WITH_VERSE
-       /* add all session to the "root" of hierarchy */
-       for(session=session_list.first; session; session = session->next) {
-               struct VNode *vnode;
-               if(session->flag & VERSE_CONNECTED) {
-                       te= outliner_add_element(soops, &soops->tree, session, NULL, ID_VS, 0);
-                       /* add all object nodes as childreen of session */
-                       for(vnode=session->nodes.lb.first; vnode; vnode=vnode->next) {
-                               if(vnode->type==V_NT_OBJECT) {
-                                       ten= outliner_add_element(soops, &te->subtree, vnode, te, ID_VN, 0);
-                                       ten->directdata= vnode;
-                               }
-                               else if(vnode->type==V_NT_BITMAP) {
-                                       ten= outliner_add_element(soops, &te->subtree, vnode, te, ID_VN, 0);
-                                       ten->directdata= vnode;
+       else if(soops->outlinevis == SO_VERSE_SESSION) {
+               /* add all session to the "root" of hierarchy */
+               for(session=session_list.first; session; session = session->next) {
+                       struct VNode *vnode;
+                       if(session->flag & VERSE_CONNECTED) {
+                               te= outliner_add_element(soops, &soops->tree, session, NULL, ID_VS, 0);
+                               /* add all object nodes as childreen of session */
+                               for(vnode=session->nodes.lb.first; vnode; vnode=vnode->next) {
+                                       if(vnode->type==V_NT_OBJECT) {
+                                               ten= outliner_add_element(soops, &te->subtree, vnode, te, ID_VN, 0);
+                                               ten->directdata= vnode;
+                                       }
+                                       else if(vnode->type==V_NT_BITMAP) {
+                                               ten= outliner_add_element(soops, &te->subtree, vnode, te, ID_VN, 0);
+                                               ten->directdata= vnode;
+                                       }
                                }
                        }
                }
        }
+       else if(soops->outlinevis == SO_VERSE_MS) {
+               te= outliner_add_element(soops, &soops->tree, "MS", NULL, ID_MS, 0);
+               if(server_list.first!=NULL) {
+                       struct VerseServer *server;
+                       /* add one main entry to root of hierarchy */
+                       for(server=server_list.first; server; server=server->next) {
+                               ten= outliner_add_element(soops, &te->subtree, server, te, ID_SS, 0);
+                               ten->directdata= server;
+                       }
+               }
+       }
 #endif
+       else {
+               ten= outliner_add_element(soops, &soops->tree, OBACT, NULL, 0, 0);
+               if(ten) ten->directdata= BASACT;
+       }
+
 
        outliner_sort(soops, &soops->tree);
 }
@@ -1643,6 +1667,30 @@ static int do_outliner_mouse_event(SpaceOops *soops, TreeElement *te, short even
                                                                break;
                                                }
                                        }
+                                       else if(te->idcode==ID_MS) {
+                                                       event = pupmenu("Verse Master Server %t| Refresh %x1");
+                                                       b_verse_ms_get();
+                                       }
+                                       else if(te->idcode==ID_SS) {
+                                               struct VerseServer *vserver = (VerseServer*)te->directdata;
+
+                                               if(!(vserver->flag & VERSE_CONNECTING) && !(vserver->flag & VERSE_CONNECTED)) {
+                                                       event = pupmenu("VerseServer %t| Connect %x1");
+                                               } else if((vserver->flag & VERSE_CONNECTING) && !(vserver->flag & VERSE_CONNECTED)) {
+                                                       event = pupmenu("VerseServer %t| Connecting... %x2");
+                                               } else if(!(vserver->flag & VERSE_CONNECTING) && (vserver->flag & VERSE_CONNECTED)) {
+                                                       event = pupmenu("VerseServer %t| Connected %x3");
+                                               }
+                                               switch(event) {
+                                                       case 1:
+                                                               b_verse_connect(vserver->ip);
+                                                               vserver->flag |= VERSE_CONNECTING;
+                                                               break;
+                                                       case 2:
+                                                       case 3:
+                                                               break;
+                                               }
+                                       }
                                }
                                else {
 #endif
@@ -2330,6 +2378,8 @@ static void tselem_draw_icon(float x, float y, TreeStoreElem *tselem, TreeElemen
                                BIF_icon_draw(x, y, ICON_WPAINT_DEHLT); break;
 #ifdef WITH_VERSE
                        case ID_VS:
+                       case ID_MS:
+                       case ID_SS:
                                BIF_icon_draw(x, y, ICON_VERSE); break;
                        case ID_VN:
                                BIF_icon_draw(x, y, ICON_VERSE); break;
@@ -2492,7 +2542,7 @@ static void outliner_draw_tree_element(SpaceOops *soops, TreeElement *te, int st
                /* open/close icon, only when sublevels, except for scene */
                if(te->subtree.first || te->idcode==ID_SCE) {
                        int icon_x;
-                       if(tselem->type==0 && (te->idcode==ID_OB || te->idcode==ID_SCE))
+                       if((tselem->type==0 && (te->idcode==ID_OB || te->idcode==ID_SCE)) || te->idcode==ID_VN || te->idcode==ID_VS || te->idcode==ID_MS || te->idcode==ID_SS)
                                icon_x = startx;
                        else
                                icon_x = startx+5;
@@ -2583,7 +2633,7 @@ static void outliner_draw_hierarchy(SpaceOops *soops, ListBase *lb, int startx,
                tselem= TREESTORE(te);
                
                /* horizontal line? */
-               if(tselem->type==0 && (te->idcode==ID_OB || te->idcode==ID_SCE)) 
+               if((tselem->type==0 && (te->idcode==ID_OB || te->idcode==ID_SCE)) || ELEM4(te->idcode,ID_VS,ID_VN,ID_MS,ID_SS))
                        glRecti(startx, *starty, startx+OL_X, *starty-1);
                        
                *starty-= OL_H;
@@ -2596,7 +2646,7 @@ static void outliner_draw_hierarchy(SpaceOops *soops, ListBase *lb, int startx,
        te= lb->last;
        if(te->parent || lb->first!=lb->last) {
                tselem= TREESTORE(te);
-               if(tselem->type==0 && te->idcode==ID_OB) {
+               if((tselem->type==0 && te->idcode==ID_OB) || ELEM4(te->idcode,ID_VS,ID_VN,ID_MS,ID_SS)) {
                        
                        glRecti(startx, y1+OL_H, startx+1, y2);
                }
index ccf80c3e910122873d0a8ca0e33e8facb14413cc..1971452d2fe08735dd845ec2192958144f7cae2e 100644 (file)
@@ -3015,6 +3015,14 @@ void drawinfospace(ScrArea *sa, void *spacedata)
                }
 
        } else if (U.userpref == 4) { /* system & opengl */
+
+#ifdef WITH_VERSE
+               uiDefBut(block, TEX, 0, "Verse Master: ",
+                       (xpos+edgsp),y3label+buth+5,mpref*2,buth,
+                       U.versemaster, 1.0, 63.0, 0, 0,
+                       "The Verse Master-server IP");
+#endif
+
                uiDefBut(block, LABEL,0,"Solid OpenGL light:",
                        xpos+edgsp, y3label, mpref, buth,
                        0, 0, 0, 0, 0, "");
index f2a36ca3086754c12351c8e05bc8884568499a61..6782a3f0c6a3c4fe7013ccdb75f098cf6ec354ea 100644 (file)
@@ -352,6 +352,12 @@ static void init_userdef_file(void)
        
        refresh_interface_font();
 
+#ifdef WITH_VERSE
+       if(strlen(U.versemaster)<1) {
+                       strcpy(U.versemaster, "master.uni-verse.org");
+       }
+#endif
+
 }
 
 #ifdef WITH_VERSE
index ec1ee8cf024a3ff7dd6b51ffbcd79510682ec022..4e8cf10746d4f398d4244017d88f71759fb6b6ab 100644 (file)
@@ -45,6 +45,7 @@
 #include "BIF_interface.h"
 
 extern ListBase session_list;
+extern ListBase server_list;
 
 /*
  * this function creates popup menu with all active VerseSessions
@@ -221,10 +222,26 @@ void post_node_name_set(VNode *vnode)
  */
 void post_connect_accept(VerseSession *session)
 {
+       VerseServer *server;
+       
        G.f |= G_VERSE_CONNECTED;
 
        session->counter = 0;
 
+       server = server_list.first;
+       while(server) {
+               if(strcmp(server->ip, session->address)==0) {
+                       server->flag = session->flag;
+                       break;
+               }
+               server = server->next;
+       }
+
+       allqueue(REDRAWOOPS, 0);
+}
+
+void post_server_add(void)
+{
        allqueue(REDRAWOOPS, 0);
 }
 
@@ -233,6 +250,16 @@ void post_connect_accept(VerseSession *session)
  */
 void post_connect_terminated(VerseSession *session)
 {
+       VerseServer *server;
+       server = server_list.first;
+       while(server) {
+               if(strcmp(server->ip, session->address)==0) {
+                       server->flag = 0;
+                       break;
+               }
+               server = server->next;
+       }
+
        /* if it is last session, then no other will exist ... set Global flag */
        if((session->prev==NULL) && (session->next==NULL))
                G.f &= ~G_VERSE_CONNECTED;