void SaveEachClass(class_node *c) { int i; if ((GetClassByID(c->class_id) != c) || (c->super_id != NO_SUPERCLASS && GetClassByID(c->super_id) == NULL) || (c->class_name == NULL)) { eprintf("SaveEachClass is not saving invalid class %i\n",c->class_id); return; } SaveGameWriteByte(SAVE_GAME_CLASS); SaveGameWriteInt(c->class_id); SaveGameWriteString(c->class_name); SaveGameWriteInt(c->num_properties); for (i=1;i<=c->num_properties;i++) { const char *s = GetPropertyNameByID(c,i); if (!s) { eprintf("SaveEachClass cannot find property name for index %i in %s\n",i,c->fname); continue; } SaveGameWriteString(s); } }
void ResetObject() { int i,old_objects; class_node *c; for (i=0;i<num_objects;i++) { if (!objects[i].deleted) { c = GetClassByID(objects[i].class_id); if (c == NULL) { eprintf("ResetObject can't find class id %i\n",objects[i].class_id); return; } FreeMemory(MALLOC_ID_OBJECT_PROPERTIES,objects[i].p, sizeof(prop_type)*(1+c->num_properties)); } } old_objects = max_objects; num_objects = 0; max_objects = INIT_OBJECTS; objects = (object_node *) ResizeMemory(MALLOC_ID_OBJECT,objects,old_objects*sizeof(object_node), max_objects*sizeof(object_node)); }
message_node *GetMessageByID(int class_id,int message_id,class_node **found_class) { class_node *c; message_node *m; int i; c = GetClassByID(class_id); if (c == NULL) { eprintf("GetMessageByID can't find class %i\n",class_id); return NULL; } do { m = c->messages; for (i=0;i<c->num_messages;i++) { if (m[i].message_id == message_id) { if (found_class != NULL) *found_class = c; return &m[i]; } } c = c->super_ptr; } while (c != NULL); return NULL; }
void SetClassNumMessages(int class_id,int num_messages) { class_node *c; int i; c = GetClassByID(class_id); if (c == NULL) { eprintf("SetClassNumMessages can't find class %i\n",class_id); return; } if (num_messages == 0) return; c->messages = (message_node *)AllocateMemory(MALLOC_ID_MESSAGE, num_messages*sizeof(message_node)); c->num_messages = num_messages; for (i=0;i<c->num_messages;i++) { c->messages[i].message_id = 0; c->messages[i].handler = 0; c->messages[i].dstr_id = INVALID_DSTR; c->messages[i].trace_session_id = INVALID_ID; c->messages[i].timed_call_count = 0; c->messages[i].untimed_call_count = 0; c->messages[i].total_call_time = 0.0; c->messages[i].propagate_message = NULL; c->messages[i].propagate_class = NULL; } }
__inline void StoreValue(int object_id,local_var_type *local_vars,int data_type,int data, val_type new_data) { class_node *class_data; object_node *o; if (kod_stat.debugging) { if (new_data.v.tag == TAG_INVALID) eprintf("[%s] StoreValue trying to assign with uninitialized data (INVALID %i)\n", BlakodDebugInfo(),new_data.v.data); } switch (data_type) { case LOCAL_VAR : if (data < 0 || data >= local_vars->num_locals) { eprintf("[%s] StoreValue can't write to illegal local var %i\n", BlakodDebugInfo(),data); return; } local_vars->locals[data].int_val = new_data.int_val; break; case PROPERTY : o = GetObjectByID(object_id); if (o == NULL) { eprintf("[%s] StoreValue can't find object %i\n", BlakodDebugInfo(),object_id); return; } class_data = GetClassByID(o->class_id); if (class_data == NULL) { eprintf("[%s] StoreValue can't find class id %i\n", BlakodDebugInfo(),o->class_id); return; } /* equal to num_properties is ok, because self = prop 0 */ if (data < 0 || data > class_data->num_properties) { eprintf("[%s] StoreValue can't write to illegal property %i (max %i)\n", BlakodDebugInfo(),data,class_data->num_properties); return; } o->p[data].val.int_val = new_data.int_val; break; default : eprintf("[%s] StoreValue can't identify type %i\n", BlakodDebugInfo(),data_type); break; } }
void SendClassMessage(object_node *object) { class_node *c = GetClassByID(object->class_id); do { if (c->class_id == classMsg.class_id) { SendBlakodMessage(object->object_id,classMsg.message_id,classMsg.num_params,classMsg.parm); numExecuted++; return; } c = c->super_ptr; } while (c != NULL); }
object_node * GetObjectByIDQuietly(int object_id) { if (object_id < 0 || object_id >= num_objects) { return NULL; } if (objects[object_id].deleted) { class_node* c; c = GetClassByID(objects[object_id].class_id); return NULL; } return &objects[object_id]; }
const char * GetDataName(val_type val) { resource_node *r; class_node *c; static char s[10]; val_type int_val; switch (val.v.tag) { case TAG_RESOURCE : r = GetResourceByID(val.v.data); if (r == NULL) { sprintf(s,"%i",val.v.data); return s; } if (r->resource_name == NULL) { sprintf(s,"%i",r->resource_id); return s; } return r->resource_name; case TAG_CLASS : c = GetClassByID(val.v.data); if (c == NULL) { eprintf("GetTagData error, can't find class id %i\n",val.v.data); sprintf(s,"%i",val.v.data); return s; } return c->class_name; case TAG_MESSAGE : // Message tag saving *is* supported, however is not advised as message ID // numbers can change and any resulting call could have undesired effects. eprintf("GetTagData error, message tag saving not supported %i\n",val.v.data); /* fall through */ default : /* write as positive int so no problem reading in */ int_val.v.tag = val.v.tag; int_val.v.data = val.v.data; sprintf(s,"%i",int_val.v.data); return s; } }
int AllocateObject(int class_id) { int old_objects; class_node *c; c = GetClassByID(class_id); if (c == NULL) { eprintf("AllocateObject can't find class id %i\n",class_id); return INVALID_OBJECT; } if (num_objects == max_objects) { old_objects = max_objects; max_objects = max_objects * 2; objects = (object_node *) ResizeMemory(MALLOC_ID_OBJECT,objects,old_objects*sizeof(object_node), max_objects*sizeof(object_node)); lprintf("AllocateObject resized to %i objects\n",max_objects); } objects[num_objects].object_id = num_objects; objects[num_objects].class_id = class_id; objects[num_objects].deleted = False; objects[num_objects].num_props = 1 + c->num_properties; objects[num_objects].p = (prop_type *)AllocateMemory(MALLOC_ID_OBJECT_PROPERTIES, sizeof(prop_type)*(1+c->num_properties)); if (ConfigBool(DEBUG_INITPROPERTIES)) { int i; prop_type p; p.id = 0; p.val.v.tag = TAG_INVALID; p.val.v.data = 0; for (i = 0; i < (1+c->num_properties); i++) { objects[num_objects].p[i] = p; } } return num_objects++; }
Bool SetObjectPropertyByName(int object_id,char *prop_name,val_type val) { object_node *o; class_node *c; int property_id; o = GetObjectByID(object_id); if (o == NULL) { eprintf("SetObjectPropertyByName can't find object %i\n",object_id); return False; } c = GetClassByID(o->class_id); if (c == NULL) { eprintf("SetObjectPropertyByName can't find class %i\n", o->class_id); return False; } property_id = GetPropertyIDByName(c,prop_name); if (property_id == INVALID_PROPERTY) { eprintf("SetObjectPropertyByName can't find property %s in class %s (%i)\n", prop_name, c->class_name, c->class_id); return False; } if (o->num_props <= property_id) { eprintf("SetObjectPropertyByName property index/id %i not in object %i class %s (%i)\n", property_id,object_id,c->class_name,c->class_id); return False; } if (o->p[property_id].id != property_id) { eprintf("SetObjectPropertyByName property index/id mismatch %i %i\n", property_id,o->p[property_id].id); return False; } o->p[property_id].val = val; return True; }
object_node * GetObjectByID(int object_id) { if (object_id < 0 || object_id >= num_objects) { eprintf("GetObjectByID can't retrieve invalid object %i\n",object_id); return NULL; } if (objects[object_id].deleted) { class_node* c; c = GetClassByID(objects[object_id].class_id); if (c) eprintf("GetObjectByID can't retrieve deleted OBJECT %i which was CLASS %s\n",object_id,c->class_name); else eprintf("GetObjectByID can't retrieve deleted OBJECT %i, unknown or invalid class\n",object_id); return NULL; } return &objects[object_id]; }
int CreateObject(int class_id,int num_parms,parm_node parms[]) { int new_object_id; class_node *c; new_object_id = AllocateObject(class_id); if (new_object_id == INVALID_OBJECT) return INVALID_OBJECT; /* set self = prop 0 */ objects[new_object_id].p[0].id = 0; objects[new_object_id].p[0].val.v.tag = TAG_OBJECT; objects[new_object_id].p[0].val.v.data = new_object_id; c = GetClassByID(class_id); if (c == NULL) /* can't ever be, because AllocateObject checks */ { eprintf("CreateObject can't find class id %i\n",class_id); return INVALID_OBJECT; } SetObjectProperties(new_object_id,c); /* might not be top level message, since can be called from blakod. If it really IS a top level message, then it better not post anything, since post messages won't be handled */ if (IsInterpreting()) SendBlakodMessage(new_object_id,CONSTRUCTOR_MSG,num_parms,parms); else SendTopLevelBlakodMessage(new_object_id,CONSTRUCTOR_MSG,num_parms,parms); if (ConfigBool(DEBUG_UNINITIALIZED)) { int i; for (i = 0; i < (1+c->num_properties); i++) if (objects[new_object_id].p[i].val.v.tag == TAG_INVALID) eprintf("Uninitialized properties after constructor, class %s\n", c->class_name); } return new_object_id; }
char *BlakodDebugInfo() { static char s[100]; class_node *c; if (kod_stat.interpreting_class == INVALID_CLASS) { sprintf(s,"Server"); } else { c = GetClassByID(kod_stat.interpreting_class); if (c == NULL) sprintf(s,"Invalid class %i",kod_stat.interpreting_class); else sprintf(s,"%s (%i)",c->fname,GetSourceLine(c,bkod)); } return s; }
void AddMessage(int class_id,int count,int message_id,char *offset,int dstr_id) { class_node *c; /* count which message in the table we are setting */ c = GetClassByID(class_id); if (c == NULL) { eprintf("AddMessage can't find class %i\n",class_id); return; } c->messages[count].message_id = message_id; c->messages[count].handler = offset; c->messages[count].dstr_id = dstr_id; c->messages[count].trace_session_id = INVALID_ID; c->messages[count].called_count = 0; }
void SaveEachObject(object_node *o) { int i; class_node *c; c = GetClassByID(o->class_id); if (c == NULL) { eprintf("SaveEachObject can't get class %i\n",o->class_id); return; } SaveGameWriteByte(SAVE_GAME_OBJECT); SaveGameWriteInt(o->object_id); SaveGameWriteInt(o->class_id); SaveGameWriteInt(c->num_properties); /* remember, don't save self (p[0]) because no name for it! * loadall will set self for us, fortunately. */ /* equal to num_properties is ok, because self = prop 0 */ for (i=1;i<=c->num_properties;i++) SaveGameWriteInt(o->p[i].val.int_val); }
void DeleteBlakodObject(int object_id) { class_node *c; object_node *o; o = GetObjectByID(object_id); if (o == NULL) { eprintf("DeleteBlakodObject can't get an object by ID %i!\n",object_id); return; } c = GetClassByID(o->class_id); if (c == NULL) { eprintf("DeleteBlakodObject can't find class %i\n",o->class_id); return; } /* now remove object */ FreeMemory(MALLOC_ID_OBJECT_PROPERTIES,o->p,sizeof(prop_type)*(1+c->num_properties)); o->deleted = True; }
/* returns the return value of the blakod */ int SendBlakodMessage(int object_id,int message_id,int num_parms,parm_node parms[]) { object_node *o; class_node *c,*propagate_class; message_node *m; val_type message_ret; int prev_interpreting_class; char *prev_bkod; int propagate_depth = 0; prev_bkod = bkod; prev_interpreting_class = kod_stat.interpreting_class; o = GetObjectByID(object_id); if (o == NULL) { bprintf("SendBlakodMessage can't find OBJECT %i\n",object_id); return NIL; } c = GetClassByID(o->class_id); if (c == NULL) { eprintf("SendBlakodMessage OBJECT %i can't find CLASS %i\n", object_id,o->class_id); return NIL; } m = GetMessageByID(c->class_id,message_id,&c); if (m == NULL) { bprintf("SendBlakodMessage CLASS %s (%i) OBJECT %i can't find a handler for MESSAGE %s (%i)\n", c->class_name,c->class_id,object_id,GetNameByID(message_id),message_id); return NIL; } m->called_count++; kod_stat.num_messages++; stack[message_depth].class_id = c->class_id; stack[message_depth].message_id = m->message_id; stack[message_depth].propagate_depth = 0; stack[message_depth].num_parms = num_parms; memcpy(stack[message_depth].parms,parms,num_parms*sizeof(parm_node)); stack[message_depth].bkod_ptr = bkod; if (message_depth > 0) stack[message_depth-1].bkod_ptr = prev_bkod; message_depth++; if (message_depth > kod_stat.message_depth_highest) kod_stat.message_depth_highest = message_depth; if (message_depth >= MAX_DEPTH) { bprintf("SendBlakodMessage sending to CLASS %s (%i), depth is %i, aborted!\n", c->class_name,c->class_id,message_depth); kod_stat.interpreting_class = prev_interpreting_class; message_depth--; bkod = prev_bkod; return NIL; } if (m->trace_session_id != INVALID_ID) { trace_session_id = m->trace_session_id; m->trace_session_id = INVALID_ID; } if (trace_session_id != INVALID_ID) TraceInfo(trace_session_id,c->class_name,m->message_id,num_parms,parms); kod_stat.interpreting_class = c->class_id; bkod = m->handler; propagate_depth = 1; while (InterpretAtMessage(object_id,c,m,num_parms,parms,&message_ret) == RETURN_PROPAGATE) { propagate_class = m->propagate_class; m = m->propagate_message; if (m == NULL) { bprintf("SendBlakodMessage can't propagate MESSAGE %s (%i) in CLASS %s (%i)\n", GetNameByID(message_id),message_id,c->class_name,c->class_id); message_depth -= propagate_depth; kod_stat.interpreting_class = prev_interpreting_class; bkod = prev_bkod; return NIL; } if (propagate_class == NULL) { bprintf("SendBlakodMessage can't find class to propagate to, from " "MESSAGE %s (%i) in CLASS %s (%i)\n",GetNameByID(message_id),message_id,c->class_name,c->class_id); message_depth -= propagate_depth; kod_stat.interpreting_class = prev_interpreting_class; bkod = prev_bkod; return NIL; } c = propagate_class; m->called_count++; if (m->trace_session_id != INVALID_ID) { trace_session_id = m->trace_session_id; m->trace_session_id = INVALID_ID; } if (trace_session_id != INVALID_ID) TraceInfo(trace_session_id,"(propagate)",m->message_id,num_parms,parms); kod_stat.interpreting_class = c->class_id; stack[message_depth-1].bkod_ptr = bkod; stack[message_depth].class_id = c->class_id; stack[message_depth].message_id = m->message_id; stack[message_depth].propagate_depth = propagate_depth; stack[message_depth].num_parms = num_parms; memcpy(stack[message_depth].parms,parms,num_parms*sizeof(parm_node)); stack[message_depth].bkod_ptr = m->handler; message_depth++; propagate_depth++; bkod = m->handler; } message_depth -= propagate_depth; kod_stat.interpreting_class = prev_interpreting_class; bkod = prev_bkod; return message_ret.int_val; }
/* returns the return value of the blakod */ int SendTopLevelBlakodMessage(int object_id,int message_id,int num_parms,parm_node parms[]) { int ret_val = 0; UINT64 start_time = 0; int interp_time = 0; int posts = 0; int accumulated_num_interpreted = 0; if (message_depth != 0) { eprintf("SendTopLevelBlakodMessage called with message_depth %i\n",message_depth); } kod_stat.debugging = ConfigBool(DEBUG_UNINITIALIZED); start_time = GetMilliCount(); kod_stat.num_top_level_messages++; trace_session_id = INVALID_ID; num_interpreted = 0; ret_val = SendBlakodMessage(object_id,message_id,num_parms,parms); while (post_q.next != post_q.last) { posts++; accumulated_num_interpreted += num_interpreted; num_interpreted = 0; if (accumulated_num_interpreted > 10*ConfigInt(BLAKOD_MAX_STATEMENTS)) { bprintf("SendTopLevelBlakodMessage too many instructions in posted followups\n"); dprintf("SendTopLevelBlakodMessage too many instructions in posted followups\n"); dprintf(" OBJECT %i CLASS %s MESSAGE %s (%i) some followups are being aborted\n", object_id, GetClassByID(GetObjectByID(object_id)->class_id)->class_name, GetNameByID(message_id), message_id); break; } /* posted messages' return value is ignored */ SendBlakodMessage(post_q.data[post_q.last].object_id,post_q.data[post_q.last].message_id, post_q.data[post_q.last].num_parms,post_q.data[post_q.last].parms); post_q.last = (post_q.last + 1) % MAX_POST_QUEUE; } interp_time = (int)(GetMilliCount() - start_time); kod_stat.interpreting_time += interp_time; if (interp_time > kod_stat.interpreting_time_highest) { kod_stat.interpreting_time_highest = interp_time; kod_stat.interpreting_time_message_id = message_id; kod_stat.interpreting_time_object_id = object_id; kod_stat.interpreting_time_posts = posts; } if (interp_time > 1000) { kod_stat.interpreting_time_over_second++; kod_stat.interpreting_time_message_id = message_id; kod_stat.interpreting_time_object_id = object_id; kod_stat.interpreting_time_posts = posts; } if (num_interpreted > kod_stat.num_interpreted_highest) kod_stat.num_interpreted_highest = num_interpreted; kod_stat.num_interpreted += num_interpreted; if (kod_stat.num_interpreted > 1000000000L) { kod_stat.num_interpreted -= 1000000000L; kod_stat.billions_interpreted++; } if (message_depth != 0) { eprintf("SendTopLevelBlakodMessage returning with message_depth %i\n",message_depth); } return ret_val; }
char *BlakodStackInfo() { static char buf[5000]; class_node *c; int i; buf[0] = '\0'; for (i=message_depth-1;i>=0;i--) { char s[1000]; if (stack[i].class_id == INVALID_CLASS) { sprintf(s,"Server"); } else { c = GetClassByID(stack[i].class_id); if (c == NULL) sprintf(s,"Invalid class %i",stack[i].class_id); else { char *bp; char *class_name; char buf2[200]; char parms[800]; int j; /* for current frame, stack[] has pointer at beginning of function; use current pointer instead */ bp = stack[i].bkod_ptr; if (i == message_depth-1) bp = bkod; class_name = "(unknown)"; if (c->class_name) class_name = c->class_name; /* use %.*s with a fixed string of pluses to get exactly one plus per propagate depth */ sprintf(s,"%.*s%s::%s",stack[i].propagate_depth,"++++++++++++++++++++++",class_name,GetNameByID(stack[i].message_id)); strcat(s,"("); parms[0] = '\0'; for (j=0;j<stack[i].num_parms;j++) { val_type val; val.int_val = stack[i].parms[j].value; sprintf(buf2,"#%s=%s %s",GetNameByID(stack[i].parms[j].name_id), GetTagName(val),GetDataName(val)); if (j > 0) strcat(parms,","); strcat(parms,buf2); } strcat(s,parms); strcat(s,")"); sprintf(buf2," %s (%i)",c->fname,GetSourceLine(c,bp)); strcat(s,buf2); } } if (i < message_depth-1) strcat(buf,"\n"); strcat(buf,s); if (strlen(buf) > sizeof(buf) - 1000) { strcat(buf,"\n...and more"); break; } } return buf; }