Massassi Forums Logo

This is the static archive of the Massassi Forums. The forums are closed indefinitely. Thanks for all the memories!

You can also download Super Old Archived Message Boards from when Massassi first started.

"View" counts are as of the day the forums were archived, and will no longer increase.

ForumsJedi Knight and Mysteries of the Sith Editing Forum → Jedi Knight Quadranscentennial Edition
123
Jedi Knight Quadranscentennial Edition
2023-11-20, 9:21 AM #81
You do have a good point regarding the verb names. What was going through my head was two things:
- having the verb name clarify how many arguments it wanted (especially since IntNeg and IntAbs only want 1 arg)
- having the verb name mimic the layout of the operator usage (e.g. IntSubInt(5, 4) mimics the layout of 5 - 4)
I don't think I'll change them, but I also don't love them. I am considering changing most of the "input" verbs to remove the "jkString" prefix. I hate changing verb names (making API changes) after releasing them to the wild, but it may not be too painful in this case given it's surely only you using them.

I haven't touched GetThingHeadLVec. It's pretty flawed and would need a complete rewrite; I'm more likely to leave it and make a new verb, but that's low on my list of stuff I want to do.

A suggestion for the syntax when using already pushed stack vars is to put placeholders so you remember how many incoming stack entries you're going to use. Some characters are completely ignored by the COG parser, and so have no impact on the resulting bytecode, but in my opinion, help the programmer keep track of where they're using stack entries. An example:
Code:
player;
if(mode == 3)
{
   holdAnim;
}
else if(mode == 4)
{
   povPreBlockAnim;
}
else if(mode == 5)
{
   holdAnim;
}
else if(mode == 6)
{
   povPreBlockAnim;
}
else if(mode == 1)
{
   povFireAnimR1;
}
else // if(mode == 2)
{
   povPreFireAnim;
}
jkPlayPOVKey(@` @` 0, 0x14);
mountAnimID = StackExchange();

Note my use of @ as a placeholder for a stack entry, and ` as a placeholder for ,. It's not perfect, but it lets me stay on top of jkPlayPOVKey wanting 4 arguments, and where the existing stack entries are used versus the two additional ones I'm specifying "normally" in the parenthesis. To clarify, @ and ` do nothing and are ignored during COG parsing time and don't affect COG runtime performance; they're just there for my benefit.

This lets me search a COG for @ to see anywhere I used this crazy syntax to make sure I'm not messing it up when making later changes to the COG.

Unfortunately, I'm pretty sure what you posted doesn't work.

So, what you're wanting is:
SetThingVel(source, VectorAdd(@` VectorAdd(@` @)));
But what's actually happening is:
SetThingVel(@` VectorAdd(@` VectorAdd(@` source)));

Code:
ScaledRVec;
ScaledLVec;
ScaledUVec;
source;
VectorAdd(); // inner, consumes source and ScaledUVec, which doesn't make sense
VectorAdd(); // outer, consumes return from inner VectorAdd and ScaledLVec
SetThingVel(); // consumes return from outer VectorAdd and ScaledRVec, which doesn't make sense


You'd need to take "source" out of the SetThingVel() line, and put it up above all 3 VectorScale's.

To reiterate:
SetThingVel(thing, VectorAdd(vec1, VectorAdd(vec2, vec3)));
Decomposes as:
Code:
thing;
vec1;
vec2;
vec3;
VectorAdd(); // inner
VectorAdd(); // outer
SetThingVel();

And:
SetThingVel(thing, VectorAdd(VectorAdd(vec1, vec2), vec3));
Decomposes as:
Code:
thing;
vec1;
vec2;
VectorAdd(); // inner
vec3;
VectorAdd(); // outer
SetThingVel();


...I think. I'm not checking these by looking at the compiled bytecode to be sure, just going based on when I have done that.... jeez, I dunno how many years ago.

Doing stuff like this can easily lead to mistakes. Assignment (=) is probably the most common gotcha, because the variable to be assigned to normally would have had to have been pushed onto the stack first (in my example, at the top before player;). Nested verbs can also (as seen) lead to mistakes.

I'm all for this though; syntax parsers are made to be abused, and the more you do stuff like this both the better you know the tool(s) you're using, and in the case of COG, you can squeeze more performance out of it. Also, it tends to be fun. This is all for fun; pretensions like maintainable code can go screw.

QM

Edit: Thinking on it, this could be a situation to use StackExchange():
Code:
ScaledRVec;
ScaledLVec;
ScaledUVec;
SetThingVel(StackExchange(VectorAdd(@` VectorAdd(@` @)), source));

...should work. Makes the code clear as mud, but eh.

Note that StackExchange() does not need to contain the two stack entries it's exchanging as arguments. This was so it could all be a (semi)logical one-liner.



Edit 2: JK 2023 rev212, cogext 2023 rev020:
https://drive.google.com/file/d/1pw35pXi3MIiOvWZhUcRMsrWc-4n4pXfO/view
https://drive.google.com/file/d/1wJn6j6Lnw1sx6pqvkKRGL2zlYt7p54O7/view

JK patch is just to support a new cogext feature. Adding hierarchy nodes to a 3do after it's in use blows the game up. Or it did, not anymore.

New cogext verbs:
AppendThingMaterial(thing, mat); returns index of new mat, clones model if not already a clone
AppendModelMaterial(model, mat); returns index of new mat, can't add a dynamic mat to a static model
AppendThingEmptyMesh(thing, mesh_name_string); returns index of new mesh, clones model if not already a clone
AppendModelEmptyMesh(model, mesh_name_string); returns index of new mesh, use this with SetModelMesh (etc.)
AppendModelNode(model, int_flags, int_type, mesh_index_or_name_string, parent_node_index_or_name_string, vector_xyz, vector_pyr, vector_pivot, node_name_string); returns index of new node, 9 arguments!

No AppendThingNode yet. Appending a hierarchy node is apparently not something that the game was designed to accommodate; was tough enough getting all the kinks worked out without automatic cloning. Also, I've found that it's pretty useful for modifying models that aren't clones (e.g. adding a right hand to vanilla player models at runtime).

The two AppendMaterial verbs are borderline useless, but I made them first to ease myself into the much more difficult AppendMesh and especially AppendNode verbs.

I intend to do a bunch of support verbs for manipulating nodes, but needed a break after I got the core feature working.

Here's some example COG:
Code:
loading:
   player = GetLocalPlayerThing();
   Sleep(1e-45); // wait for multiplayer model assignment
   m = GetThingModel(player);
   if(GetModelNodeCount(m) == 18)
   {
      AppendModelNode(m, 0x0000, 0x00001, -1, "k_torso", '0 0 0', '', '', "Object01");
      i = AppendModelEmptyMesh(m, "k_rhand_");
      SetModelMesh(m, i, LoadModel("fistg.3do"), 0);
      AppendModelNode(m, 0x0000, 0x00004, i, "k_rhand", '0 0 0', '', '-0.002488 0.009120 -0.005542', "k_rhand_");


#      "fistg.3do";call _deglove;
      "bryg.3do"; call _deglove;
      "strg.3do"; call _deglove;
      "detg.3do"; call _deglove;
      "bowg.3do"; call _deglove;
      "rptg.3do"; call _deglove;
      "rldg.3do"; call _deglove;
      "seqg.3do"; call _deglove;
      "cong.3do"; call _deglove;
      "sabg.3do"; call _deglove;
   }
   Return;


_deglove:
   LoadModel(@);
   m = StackExchange();
   ReplaceModelMaterial(m, LoadMaterial("kyhand.mat"), -1);
   ReplaceModelMaterial(m, LoadMaterial("kyhandf.mat"), -1);
   Return;
2023-11-22, 9:13 AM #82
Oh, this will make rendering text strings into a single thing SO MUCH easier. Thank you.

That said! I'm afraid I could easily run into some limits depending on how many different lines of text I'd need, so in case I might want to reuse some existing but unused cloned models, something like ClearModel(int model) to remove all meshes and nodes from a 3do kind of become a necessity, especially considering something like FreeModel() is not practical at all. Maybe ClearModelNode()/ClearModelMesh() could be better? idk.


Also correct me if I'm wrong, but CloneModel() won't work if there aren't any free 3do indexes in the current level's JKL, right? Doesn't that mean most times it won't work at all since JED automatically sets the World models section in the level's JKL to the bare minimum necessary? I had to manually increase that value in a level JKL for CloneModel() to work. What are the downsides of bypassing that value altogether in a future patch?
JKGR
2023-11-22, 2:23 PM #83
Oh, it does... stupid JED. The vanilla levels have higher model counts than the number they use, and I'd been doing almost all of my testing in vanilla levels. Other than a little more memory use (I think 132 bytes per model count), padding the dynamic (level) model count shouldn't cause problems. If I bump the model count by 100 above what the level asks for, that'd be 4 more pages of memory (a page is 4096 bytes), so that's not too horrible.

The same would be true if I do any sort of sprite cloning.

I'm sort've confused though as it seems like I can LoadResource whatever in whatever level... maybe I'm just getting lucky and only trying things that happen to already be loaded. I don't see any code that's realloc'ing on demand when limits are hit that would explain when it works. And I'm not sure why multiplayer models aren't always butting up against the limit. Hm...

Some sort of ClearModel / ClearModelMesh verbs should be possible. ClearModelNode would be a lot of work (have to unhook it from the hierarchy and junk) and I don't think I'd want to tackle that. I can likely add an AmputateNode verb that'd at least let you hide them without setting their mesh to -1 (and even if they aren't specified by a joint). ClearModel would likely leave the hierarchy intact, just with all meshes set to -1.

QM
2023-11-22, 3:31 PM #84
Re.: Multiplayer models, maybe they're loaded as static resources upon game startup? I know items.dat cogs are, so it'd make perfect sense for models.dat models to also be.


I imagined something like ClearModelNode() would be difficult to implement, that's why I though of ClearModel() which would just delete all nodes and meshes altogether with very little concern (or so I imagined) for hierarchies and the such. The very specific reason I see why one would need something like that is for reusing the index for a previously cloned model for another, maybe completely different model. Maybe something like OverwriteModel(sourceModel, modelIndex) for cloning a model over an already existing one would be easier?

If not, I suppose something like SetModelNodeOffset(int model, int node, vec position), which hopefully should be way easier, would be good enough.


Edit: SetModelNodeOffset() would inevitably lead us to GetModelNodeOffset(), which makes me wonder - is something like GetThingNodePos(), taking into account the current animations a thing is playing, as far fetched as I imagine it is? IIRC something of that sort exists in Infernal Machine, but there's probably a ton of different stuff in the engine to make such verb possible. Then again, JK must surely keep track of node positions somehow for rendering the saber blade and stuff.


Edit 2.: While we're at it, maybe the "-noThingLimit" command line switch (added in your 2018 patch IIRC) could be extended to bypass resource limits as well?
Also, I'm not sure about the specifics but spawning too many things in levels with a thing limit beyond that of vanilla can cause the game to crash when used along with said switch.
JKGR
2023-11-23, 10:41 PM #85
Happy Patchgiving. JK 2023 rev213, cogext 2023 rev021:
https://drive.google.com/file/d/1zhcb1EhMa-rmD6zaHsiVC37pJJAq_AHm/view
https://drive.google.com/file/d/1nWccAqIAWn25y21iZbLXOfluy0sNgcW3/view

The JK patch fixes the -nothinglimit crash and adds support for unanimated model nodes (i.e. nodes with an index higher than any animations used on their model use, so 19+ for the typical player animations) to have RLU overrides (i.e. so you can invert their RVec to mirror them). -nothinglimit now means a limit of 46768, down from 65535.

Quite a few new cogext verbs and such:
- SetThingMesh/SetModelMesh/SwapModelMesh now accept a model name as a string for the input model, in which case the model is directly loaded into a temporary buffer, the desired mesh on them is used, then that temporary model is freed. This is slow, especially if you want multiple meshes from the same model as it will load and unload for each mesh, but lets you do things not possible otherwise (getting pieces from a model you don't want to permanently load for the current level).
- GetThingNodeCount(thing); returns int number of nodes currently allocated, if you append a node to a thing's model, this will tell you if the new nodes have been populated on the thing yet; only really of technical value, getting the node count on the thing's model is going to generally be more useful
- GetThingNodeRLUVecs(thing, node_index); returns 3 vectors, these values aren't of huge value and was more of an experiment as I got other verbs working
- GetModelMesh(model, mesh_name_string); returns int mesh index, case sensitive, so can give false negatives, I'll likely make it a case insensitive comparison
- GetModelNode(model, node_name_string); returns int node index, case sensitive, so can give false negatives, I'll likely make it a case insensitive comparison
- GetModelNodePos(model, node_index); returns vector, this is the literal value defined on the model's hierarchy node
- GetModelNodePYR(model, node_index); returns vector, this is the literal value defined on the model's hierarchy node
- GetModelNodeRLUVecs(model, node_index); returns 3 vectors
- SetModelNodeRLUVecs(model, node_index, rvec, lvec, uvec);
- GetModelNodePivot(model, node_index); returns vector, this is the literal value defined on the model's hierarchy node
- SetModelNodePivot(model, node_index, vector);
- IsModelMeshEmpty(model, mesh_index); returns 1 if mesh has no vertices or faces, or if an invalid mesh_index is given, 0 otherwise

And some example COG:
Code:
loading:
   player = GetLocalPlayerThing();
   if(IsMulti()) Sleep(1e-45); // wait for multiplayer model assignment
   m = GetThingModel(player);
   p = GetThingPuppet(player);
   if(GetModelNodeCount(m) == 18)
   {
      n = GetPuppetJointNode(p, 2); // torso
      AppendModelNode(m, 0x0000, 0x00001, -1, n, '0 0 0', '', '', "Object01");
   }
   n = GetPuppetJointNode(p, 3); // rhand
   o = GetPuppetJointNode(p, 4); // lhand
   if(o == n)
   {
      o = GetModelNode(m, "k_lhand");
      if(o == -1) o = 6;
      SetPuppetJointNode(p, 4, 0); // lhand
   }
   if(IsModelMeshEmpty(m, GetModelNodeMesh(m, n)) && GetModelNodeChildCount(m, n) == 0)
   {
      l = GetModelNodeMesh(m, o);
      if(l == -1) l == GetModelMesh(m, "k_lhand");

      r = AppendModelEmptyMesh(m, "k_rhand_");
#      SetModelMesh(m, r, "fistg.3do", 0);
#      AppendModelNode(m, 0x0000, 0x00004, r, n, '0 0 0', '', '-0.002488 0.009120 -0.005542', "k_rhand_");
      SetModelMesh(m, r, m, l);
      n = AppendModelNode(m, 0x0000, 0x00004, r, n, '0 0 0', '', GetModelNodePivot(m, o), "k_rhand_");

      GetModelNodeRLUVecs(m, n);
      uvec = StackExchange();
      lvec = StackExchange();
      rvec = StackExchange();
      SetModelNodeRLUVecs(m, n, VectorScale(rvec, -1), lvec, uvec);
   }
   if(GetModelMaterial(LoadModel("fistg.3do"), 0) == LoadMaterial("kyhand.mat"))
   {
      "fistg.3do";call _deglove;
      "bryg.3do"; call _deglove;
      "strg.3do"; call _deglove;
      "detg.3do"; call _deglove;
      "bowg.3do"; call _deglove;
      "rptg.3do"; call _deglove;
      "rldg.3do"; call _deglove;
      "seqg.3do"; call _deglove;
      "cong.3do"; call _deglove;
      "sabg.3do"; call _deglove;
      "rep0.3do"; call _deglove;
   }
   Return;

_deglove:
   LoadModel(@);
   m2 = StackExchange();
   ReplaceModelMaterial(m2, LoadMaterial("kyhand.mat"), -1);
   ReplaceModelMaterial(m2, LoadMaterial("kyhandf.mat"), -1);
   Return;

QM



Edit: JK 2023 rev212, cogext 2023 rev022:
https://drive.google.com/file/d/1MgvzVnC_9ptRnze22rNQfS5km7e6_YCU/view
https://drive.google.com/file/d/1V0gq-et7snFUJokERYumZW2ySgsps10I/view

JK patch makes levels allocate an extra 100 model slots. Didn't seem worth hooking it up to a switch of any sort. Static model slots (via static.jkl) still match what static.jkl specifies.

cogext is a doozy, let's see...
- modified node and mesh verbs that accept strings for node names and mesh names to do a case-insensitive comparison (i.e. K_LHAND == k_lhand == K_LHand, etc.)
- SetModelNodeMesh now allows setting a node mesh to -1
- ReplaceModelMaterial now scans all meshes for a match even if the model's material list is empty
- for verbs that can load a temporary model, the temp model now counts as static if all materials it uses are static for purposes of allowing mesh copies

- ReplaceModelMeshMaterial(model, mesh_index_or_name_string, mat_old, mat_new); mesh version of ReplaceModelMaterial; doesn't affect the model's material list
- ClearModel(model); strips it down to a single empty geoset, 0 materials, 0 meshes, 0 nodes
- ClearModelMesh(model, mesh_index); strips it down to an empty mesh on all geosets
- OverwriteModel(model_destination, model_source); frees the destination model, then copies from the source model; cannot overwrite a static model with a dynamic model
- ReloadModel(model); reloads the model from 3do file as specified by the model's own data; clones will reload from whatever their base model was
- SetModelNodePos(model, node_index, vector); sets the node's offset (called pos in the hierarchy table) then recalculates its RLU vectors
- SetModelNodePYR(model, node_index, vector); sets the node's PYR vector then recalculates its RLU vectors
- GetModelOffset(model); returns vector, literal value as specified in the model's 3do
- SetModelOffset(model, vector); not sure if this has any effect
- GetModelRadius(model); returns float, literal value as specified in the model's 3do
- GetModelMeshRadius(model, mesh_index); returns float, literal value as specified in the model's 3do
- GetThingJointMesh(thing, joint_index); returns int index of mesh or -1 if invalid; if the initial node has a -1 mesh, it traverses the node's children and returns the first mesh that's not -1 (if such exists)

Note that some verbs do not allow using mesh or node names, just indexes.



Edit 2: Stumbled upon a screwy bug in vanilla JK: in multiplayer, the loading COG message occurs before the level timers have been reset. This means if you load an MP level as anything but the first level after starting the game, Sleep's and other timing-related COG messages (Timer, Pulse, GameTime) set up in a loading message will get a timestamp related to how long you'd been in the previous level, meaning Sleep's etc. won't fire for a potentially very long time. If you were in the previous level for 5 minutes, in the newly loaded level, the earliest a Sleep within a loading message would expire would be after 5 minutes.

I won't be fixing this. So just be aware not to use time-related verbs in a loading message in multiplayer as they will not behave correctly except during the very first level loaded. You can use GetGameTime() in a loading message and if it's not 0, you're seeing the bug.
2023-11-27, 6:13 AM #86
Oh, that's a big one.

I'm yet to test everything, but CloneModel() in CogExt rev022 seems to be crashing the game. I'm trying to clone a static model.
JKGR
2023-11-27, 9:59 AM #87
Whoops, I had to reorganize some code related to CloneModel to get OverwriteModel working and a mistake slipped through. Verbs that autoclone worked so I neglected to test CloneModel itself. Is fixed for the next release. As is a crash on resource free when exiting a level that supported 32 players.

QM



Edit: JK 2023 rev215, cogext 2023 rev023:
https://drive.google.com/file/d/1Fhq15jJCoRFtvHfcrWijjqY3-VMhT7cA/view
https://drive.google.com/file/d/17QjmkoZmxpWTX3KgpdDD5tkyjGCY74Oc/view

The JK patch fixes a crash on level end for levels that support 32 players.

The cogext patch fixes CloneModel, improves SetThingHeadPYR to set joints as applicable and adds the following verbs:
- AmputateNode(thing, node_index); amputates a node, like amputate joint, but without the puppet intermediary
- RestoreNode(thing, node_index); restores a previously amputated node
- IsNodeAmputated(thing, node_index); returns 1 or 0 depending on if the requested node is amputated; returns -1 if invalid
- IsJointAmputated(thing, joint_index); returns 1 or 0 depending on if the requested joint is amputated; returns -1 if invalid
- GetBaseModel(model); returns int model index of the non-cloned model a clone is based on; returns the input if not a clone; returns -1 if invalid
- LoadStaticMaterial(material_filename); returns int material index of a material forced to load as a static resource; will return -1 if there are no free static material slots left; if the material is already loaded, you'll get that result instead, check the result & 0x8000 to see if it's actually static
- LoadStaticModel(model_filename); returns int model index of a model forced to load as a static resource; will return -1 if there are no free static model slots left; if the model is already loaded, you'll get that result instead, check the result & 0x8000 to see if it's actually static

All 3 AmputateJoint verbs (AmputateJoint, RestoreJoint, IsJointAmputated) risk a crash (or other bad behavior) if used on a joint freshly reassigned to a newly appended node on a model, if the thing having the AmputateJoint verb used on it hasn't refreshed its thing node hierarchy yet. Three ways to deal with this:
1) don't dynamically reassign joints to newly appended nodes
2) use the AmputateNode verbs, which force a thing node hierarchy refresh if needed so are always safe
3) use IsNodeAmputated(thing, 0) to force a node hierarchy refresh before using an AmputateJoint verb on the thing
Again though, this only matters if reassigning joints. If You append a node but don't change any joints to use the new nodes, no risk with the AmputateJoint verbs.

A thing node hierarchy refresh only occurs passively if the thing's model is currently rendering, so one obvious case is if the player is in first-person, their model will not passively have its node hierarchy refreshed.

This may have finished all the runtime model manipulation verbs I had in mind.



Edit 2: I worked out why multiplayer models generally load successfully. The game definitely doesn't pre-load models.dat: big MP model packs of the late 90s would've wrecked computers of the time. No, it's kinda dumber: with the vanilla static.jkl, a typical JED-created level has ~26 of the same models specified as static.jkl, and when they're a match, it doesn't reload them, so you wind up with a free slot in the dynamic (level) model list. Those ~26 slots are where multiplayer models fit. I'm guessing for JKGR, your static.jkl model list and your levels have little to no overlap so you don't end up with free slots for CloneModel (etc.). Again though, I already added in a 100 model slots padding to level loads, so under reasonable circumstances, that'll be plenty. Just finally took the time to figure out why it's generally not a problem in vanilla.

Which then prompts the question, what about soundclasses? static.jkl only defines 1, and JED spits out levels with no padding in the soundclasses list, so is there only 1 free soundclass slot? Well, the game pads the dynamic soundclass list by 32 when loading a level in multiplayer; one for each max possible player. -_-



Edit 3: JK 2023 rev216, cogext 2023 rev024:
https://drive.google.com/file/d/1IcfqJj3DLwFGQfhIhnSoYCZUosTXc7d_/view
https://drive.google.com/file/d/1G01vkS-DNaV-WPEfVc3XUKQnUmRwon0n/view

The JK patch adds a new -noCogExt commandline argument that disables new COG verbs and messages.

The cogext patch fixes Get/SetThingFlashRGB, and adds some new verbs:
- GetMaximalThing(); returns int thing index of probably the thing with the highest index number, maybe
- GetLastSound(); returns int sound channel of the most recent sound; these aren't simple index numbers and are the type that can be used with StopSound
- StopThingSounds(thing, flex_delay_fade_out); stops all sounds associated with the specified thing; like with StopSound use 0.0 to stop immediately; should synchronize in multiplayer
- GetPlayingSound(sound); returns int sound channel of the sound specified with an attempt made for it to be the most recent copy of that sound if multiple of it are playing, or 0 if none found; 0 because that's the "correct" unavailable sound channel value (instead of -1)
- GetSoundClassSound(soundclass, subclass); returns int sound index or -1 if invalid



Edit 4: cogext 2023 rev025:
https://drive.google.com/file/d/1GmJCQNUkqZJrJOe_rhfygyo3Fxhd9riT/view

For reference, in the following verbs, "track" is referring to the value returned by PlayKey / PlayMode (et. al.): a keyframe animation track index.

New cogext verbs:
- GetKeySpeed(keyframe); returns float keyframe animation speed in frames per second (fps), -1 if invalid
- SetKeySpeed(keyframe, float_fps); sets animation speed for all subsequent use of the specified keyframe animation, positive values only
- GetThingTrackSpeed(thing, track_index); returns float keyframe animation speed in frames per second (fps), -1 if invalid
- SetThingTrackSpeed(thing, track_index, float_fps); sets animation speed for currently playing animation, positive values only
- GetThingTrackKey(thing, track_index); returns int keyframe animation index currently using the specified track, -1 if invalid
- GetPOVTrackSpeed(thing, track_index); returns float keyframe animation speed in frames per second (fps), -1 if invalid
- SetPOVTrackSpeed(thing, track_index, float_fps); sets animation speed for currently playing animation, positive values only
- GetPOVTrackKey(thing, track_index); returns int keyframe animation index currently using the specified track, -1 if invalid
- GetThingModeKey(thing, int_mode); returns int keyframe animation index based on the thing's current major mode (armed mode + swimming state), -1 if none or invalid
- GetPuppetMajorModeKey(puppet, int_major_mode, int_mode); returns int keyframe animation index, -1 if none or invalid

The speed verbs don't sync in multiplayer.



Edit 5: JK 2023 rev217, cogext 2023 rev026:
https://drive.google.com/file/d/1FNHhq5rATMqTxYqDr7oYKKsQCuiIgpNE/view
https://drive.google.com/file/d/12XmPqBEjzDmL0iOw9XWVqWv0AyyugHQ8/view

The JK patch hooks up the camera collision size to a variable for use by cogext verbs and does a little memleak fixing related to cameras.
Also tweaks camera 0 to collide with things if it's displaced using SetPOVShake.

The cogext patch enhances LoadStaticMaterial/Model so they will replace a dynamic (level) Material/Model with a static one.
Fixes camera zoom and FOV verbs to not trash memory if used on cameras > 2 and to correctly set aspect ratio.
Replaces some hardcoded camera 0/1 references so the code will work on any camera number.
Also adds the following verbs:
- GetCameraCollideSize(); returns float collide size of all cameras, default 0.02
- SetCameraCollideSize(float); sets collide size of all cameras
- GetCurrentCameraRLUVecs(camera_index); returns 3 vectors
- GetCurrentCameraPos(camera_index); returns vector
- GetCurrentCameraPYR(camera_index); returns vector
- SetCamera2RLUVecs(rvec, lvec, uvec);
- SetCamera2Pos(vector);
- SetCamera2Sector(sector_index);

Be sure to set a valid sector for camera 2 before using SetCurrentCamera(2);

The beefed up LoadStaticModel won't stop you from causing a static model that uses dynamic textures to occur, which can be crashy when you change levels, so use with caution. LoadStaticMaterial is safe, though you may fill up the static material list. If you iterate through a model's materials checking if they're static and calling LoadStaticMaterial on ones that aren't (tedious, as it requires a lot of jkStringConcatMaterialName), and then call LoadStaticModel on the model (or ReloadModel if it's already static), that should create a safe static model at runtime. Probably.

Edit 6: There's a mistake in GetModelNode, the crashy kind; don't use it until the next update.



Edit 7: JK 2023 rev218, cogext 2023 rev027:
https://drive.google.com/file/d/16SZeARRFCGmyLM5t-aUrSWLAu40zgXcy/view
https://drive.google.com/file/d/1AsxTU3Z_Xnb52MQm3x0wM8wM6tO9siS5/view

The JK patch makes a slight tweak to camera 0 collision: it no longer collides unless displacing it forward by at least 0.125 JKUs.

The cogext patch fixes GetModelNode and adds a few new verbs:
- SetCamera2Look(lvec); avoids needing to do a full RLU vector set if just trying to do a simple camera setup; like SetThingLook, you do not need to normalize the input vector (both always normalize their input)
- TeleportCamera2(thing); sets camera 2's sector, position and RLUvecs by copying a thing's values
- jkStringConcatChar(int); can handle wide chars, so supports input values from 1 to 65535 (0xFFFF)
- VectorLenSq(vector); like VectorLen but doesn't squareroot the result so is much faster; especially useful when comparing against a fixed value
- VectorDistSq(vector, vector); like VectorDist but doesn't squareroot the result so is much faster; especially useful when comparing against a fixed value

The main thing I was working on (other than some COGs), was enhancing cogext's floating point optimization... thing. In addition to all ftol function calls that I'd optimized previously, 90% of floor and ceiling operations are now faster. The other 10% I haven't been able to fit the necessary replacement code in-place. For reference, JK uses floor in 986 places and ceiling in 108 places, and I optimized 892 and 96 of them, respectively.

That said, the code is wildly different, and while I think I implemented things correctly to get exactly vanilla results, I am not yet 100% positive. It seems to be right, so if something is off, I suspect it'd be extremely subtle.
2023-12-07, 5:55 PM #88
Again, I'm yet to test everything but the something about the latest CogExt patch seems to be causing the game to crash (with JKGR at least, unmodded JK runs fine).

Code:
Unhandled exception: page fault on write access to 0x00000009 in 32-bit code (0x1004a03f).
Register dump:
 CS:0023 SS:002b DS:002b ES:002b FS:0063 GS:006b
 EIP:1004a03f ESP:009ffb40 EBP:009ffc14 EFLAGS:00010206(  R- --  I   - -P- )
 EAX:008ec2c0 EBX:00000001 ECX:42d20000 EDX:00000000
 ESI:009ffc24 EDI:009ffd44
Stack dump:
0x009ffb40:  00000000 00000001 009ffd44 009ffc24
0x009ffb50:  00000001 129ff368 14313000 032b0000
0x009ffb60:  00000000 00001003 009ffbd8 7bc2540b
0x009ffb70:  00000002 00000000 00000020 009ffc3c
0x009ffb80:  1308fbb8 129fe338 0051452f 00000002
0x009ffb90:  00000014 005144e3 00000014 0000000c
Backtrace:
=>0 0x1004a03f in jk (+0x4a03f) (0x009ffc14)
  1 0x1004a422 in jk (+0x4a422) (0x009ffd44)
0x1004a03f jk+0x4a03f: movl    %ecx,0x8(%ebx)
Modules:
Module    Address            Debug info    Name (130 modules)
PE    00370000-00385000    Deferred        portable
PE    00390000-003ab000    Deferred        winmm
PE    003b0000-003c6000    Deferred        smackw32
PE    00400000-008f4000    Export          jk23
PE    00d00000-01ed5000    Deferred        wined3d
PE    01ee0000-022cf000    Deferred        ole32
PE    022d0000-026a7000    Deferred        comctl32
PE    038b0000-03a15000    Deferred        winmm
PE    04be0000-04bf2000    Deferred        a3d
PE    04e00000-04e97000    Deferred        mmdevapi
PE    04ea0000-04f12000    Deferred        winepulse
PE    05040000-050ee000    Deferred        dinput8
PE    05760000-05adc000    Deferred        oleaut32
PE    10000000-1010a000    Export          jk
PE    5e080000-5e0bb000    Deferred        dplayx
ELF    63431000-64a80000    Deferred        iris_dri.so
PE    64a80000-64acc000    Deferred        win32u
PE    65480000-65662000    Deferred        rpcrt4
PE    65680000-65875000    Deferred        msvcrt
PE    66080000-660d5000    Deferred        msacm32
PE    66640000-6665a000    Deferred        version
PE    67500000-67544000    Deferred        imm32
PE    67c00000-67d83000    Deferred        dsound
PE    684c0000-685f0000    Deferred        combase
PE    68880000-68cfa000    Deferred        user32
PE    69840000-6990e000    Deferred        advapi32
PE    69ec0000-69ec6000    Deferred        ddraw
PE    6aac0000-6ad06000    Deferred        ucrtbase
PE    6aec0000-6b060000    Deferred        setupapi
PE    6b3c0000-6b405000    Deferred        libvorbisfile-3
PE    6bb40000-6bbbd000    Deferred        winex11
PE    6bbc0000-6bc4b000    Deferred        sechost
PE    6da80000-6dc21000    Deferred        gdi32
PE    6de80000-6df20000    Deferred        dinput
PE    71080000-710a4000    Deferred        hid
ELF    72e99000-739a6000    Deferred        libnvidia-glvkspirv.so.440.64
ELF    739a6000-74100000    Deferred        libvulkan_intel.so
ELF    74246000-746f7000    Deferred        libvulkan_lvp.so
ELF    746f7000-78bec000    Deferred        libllvm-10.so.1
ELF    78bec000-7a800000    Deferred        libnvidia-glcore.so.440.64
PE    7a800000-7ab6c000    Deferred        opengl32
PE    7b000000-7b479000    Deferred        kernelbase
PE    7b600000-7b72c000    Deferred        kernel32
PE    7bc00000-7be4c000    Deferred        ntdll
ELF    7c659000-7cbff000    Deferred        libvulkan_radeon.so
ELF    7cbff000-7cce7000    Deferred        libglx_nvidia.so.0
ELF    7ce04000-7ce90000    Deferred        libvorbisenc.so.2
ELF    7ce90000-7cf71000    Deferred        libgcrypt.so.20
ELF    7cf71000-7d000000    Deferred        libsndfile.so.1
ELF    7d000000-7d004000    Deferred        <wine-loader>
ELF    7d016000-7d078000    Deferred        libflac.so.8
ELF    7d61c000-7d630000    Deferred        libnss_files.so.2
ELF    7d630000-7d64b000    Deferred        libnsl.so.1
ELF    7d64b000-7d659000    Deferred        libnss_nis.so.2
ELF    7d659000-7d663000    Deferred        libnss_compat.so.2
ELF    7d76a000-7d78e000    Deferred        libtinfo.so.5
ELF    7d78e000-7d7c5000    Deferred        libedit.so.2
ELF    7d7c5000-7d7ce000    Deferred        libffi.so.6
ELF    7d7ce000-7d7d5000    Deferred        libatomic.so.1
ELF    7d7d5000-7d7ff000    Deferred        libgcc_s.so.1
ELF    7da6e000-7da78000    Deferred        libdrm_nouveau.so.2
ELF    7da78000-7da86000    Deferred        libdrm_radeon.so.1
ELF    7da86000-7da96000    Deferred        libsensors.so.4
ELF    7da96000-7da9a000    Deferred        libxcb-shm.so.0
ELF    7da9a000-7daa0000    Deferred        libxcb-dri2.so.0
ELF    7daa0000-7dabd000    Deferred        libxcb-glx.so.0
ELF    7dabd000-7dae5000    Deferred        libglapi.so.0
ELF    7dae5000-7db5c000    Deferred        libglx_mesa.so.0
ELF    7db5c000-7dbd7000    Deferred        libgldispatch.so.0
ELF    7dbda000-7dbf2000    Deferred        libgpg-error.so.0
ELF    7dbf2000-7dc0a000    Deferred        libresolv.so.2
ELF    7dc0a000-7dc35000    Deferred        libvorbis.so.0
ELF    7dc35000-7dc4b000    Deferred        liblz4.so.1
ELF    7dc4b000-7dcdb000    Deferred        libsystemd.so.0
ELF    7dcdb000-7dd36000    Deferred        libdbus-1.so.3
ELF    7de68000-7de6c000    Deferred        libxdamage.so.1
ELF    7de6c000-7dea7000    Deferred        libglx.so.0
ELF    7dea7000-7df13000    Deferred        libgl.so.1
ELF    7df16000-7df41000    Deferred        liblzma.so.5
ELF    7df41000-7dfce000    Deferred        libpulsecommon-11.1.so
ELF    7dfce000-7e028000    Deferred        libpulse.so.0
ELF    7e031000-7e038000    Deferred        libvklayer_mesa_device_select.so
ELF    7e038000-7e04a000    Deferred        libxcb-randr.so.0
ELF    7e05b000-7e0da000    Deferred        libzstd.so.1
ELF    7e0da000-7e0ef000    Deferred        libdrm.so.2
ELF    7e0ef000-7e0f2000    Deferred        libxshmfence.so.1
ELF    7e0f2000-7e0fa000    Deferred        libxcb-sync.so.1
ELF    7e0fa000-7e0fe000    Deferred        libxcb-present.so.0
ELF    7e0fe000-7e101000    Deferred        libx11-xcb.so.1
ELF    7e101000-7e10f000    Deferred        libwayland-client.so.0
ELF    7e10f000-7e121000    Deferred        libapparmor.so.1
ELF    7e121000-7e126000    Deferred        libxcb-dri3.so.0
ELF    7e126000-7e144000    Deferred        libelf.so.1
ELF    7e144000-7e150000    Deferred        libdrm_amdgpu.so.1
ELF    7e155000-7e15e000    Deferred        libogg.so.0
ELF    7e1e1000-7e1e6000    Deferred        libnvidia-tls.so.440.64
ELF    7e1e6000-7e1ed000    Deferred        libasyncns.so.0
ELF    7e1ed000-7e1f8000    Deferred        libwrap.so.0
ELF    7e1f8000-7e20b000    Deferred        winepulse.so
ELF    7e294000-7e29b000    Deferred        libxfixes.so.3
ELF    7e29b000-7e2a7000    Deferred        libxcursor.so.1
ELF    7e2da000-7e339000    Deferred        libvulkan.so.1
ELF    7e339000-7e34c000    Deferred        libxi.so.6
ELF    7e34c000-7e350000    Deferred        libxcomposite.so.1
ELF    7e350000-7e35d000    Deferred        libxrandr.so.2
ELF    7e35d000-7e369000    Deferred        libxrender.so.1
ELF    7e369000-7e370000    Deferred        libxxf86vm.so.1
ELF    7e370000-7e374000    Deferred        libxinerama.so.1
ELF    7e374000-7e37e000    Deferred        librt.so.1
ELF    7e37e000-7e399000    Deferred        libbsd.so.0
ELF    7e399000-7e3a0000    Deferred        libxdmcp.so.6
ELF    7e3a0000-7e3a5000    Deferred        libxau.so.6
ELF    7e3a5000-7e3d1000    Deferred        libxcb.so.1
ELF    7e3d1000-7e51b000    Deferred        libx11.so.6
ELF    7e51b000-7e530000    Deferred        libxext.so.6
ELF    7e563000-7e5ed000    Deferred        winex11.so
ELF    7e5ed000-7e68d000    Deferred        opengl32.so
ELF    7e809000-7e83b000    Deferred        libexpat.so.1
ELF    7e83b000-7e886000    Deferred        libfontconfig.so.1
ELF    7e886000-7e8a5000    Deferred        libz.so.1
ELF    7e8a5000-7e8df000    Deferred        libpng16.so.16
ELF    7e8df000-7e99c000    Deferred        libfreetype.so.6
ELF    7e99c000-7ea9e000    Deferred        libm.so.6
ELF    7ead1000-7ec44000    Deferred        win32u.so
ELF    7ec44000-7edcc000    Dwarf           libwine.so.1
ELF    f7cba000-f7d71000    Deferred        ntdll.so
ELF    f7d71000-f7f4d000    Deferred        libc.so.6
ELF    f7f4d000-f7f52000    Deferred        libdl.so.2
ELF    f7f52000-f7f72000    Deferred        libpthread.so.0
ELF    f7fa7000-f7fcf000    Deferred        ld-linux.so.2
Threads:
process  tid      prio    name (all IDs are in hex)
00000020 jkgr.exe
    00000024    0     
00000038 services.exe
    0000003c    0     
    00000040    0     wine_rpcrt4_server
    00000054    0     wine_rpcrt4_io
    0000007c    0     wine_rpcrt4_io
    00000090    0     wine_rpcrt4_io
    000000a8    0     wine_rpcrt4_io
    000000b4    0     wine_rpcrt4_io
    000000d8    0     wine_rpcrt4_io
    000000e8    0     wine_rpcrt4_io
    00000108    0     wine_rpcrt4_io
    00000124    0     wine_rpcrt4_io
00000044 AppleMobileDeviceService.exe
    00000048    0     
    0000005c    0     
    00000064    0     
    0000006c    0     
    00000078    0     
    00000148    0     
    0000014c    0     
    0000015c    0     
0000004c explorer.exe
    00000050    0     
    000000c4    0     
    000000d0    0     
    000000d4    0     wine_rpcrt4_server
00000070 mDNSResponder.exe
    00000074    0     
    00000080    0     
    00000084    0     wine_sechost_service
00000088 svchost.exe
    0000008c    0     
    00000094    0     
    0000009c    0     wine_sechost_service
000000a0 winedevice.exe
    000000a4    0     
    000000ac    0     
    000000b0    0     wine_sechost_service
    000000b8    0     
    000000bc    0     
    000000c0    0     
    00000118    0     
000000c8 winedevice.exe
    000000cc    0     
    000000dc    0     
    000000e4    0     wine_sechost_service
    000000ec    0     
    000000f0    0     
    000000f4    0     
    00000100    0     
    00000104    0     
000000f8 plugplay.exe
    000000fc    0     
    0000010c    0     
    00000110    0     wine_sechost_service
    00000114    0     wine_rpcrt4_server
0000011c rpcss.exe
    00000120    0     
    00000128    0     
    0000012c    0     wine_sechost_service
    00000130    0     wine_rpcrt4_server
    00000134    0     wine_rpcrt4_server
    00000138    0     wine_rpcrt4_io
00000140 (D) E:\JK\jk23.exe
    00000144    0 <== 
    00000150    0     
    00000160   15     
    00000164    0     
    00000168   15     winepulse_mainloop
    0000016c   15     winepulse_timer_loop
    00000170   15     wine_dsound_mixer
    00000178    0     
    0000017c    0     
    00000180    0     
    00000184    0     wine_mmdevapi_notification
    00000188   15     winepulse_timer_loop
    0000018c    0     wined3d_cs
    00000198    0     
System information:
    Wine build: wine-8.0.1
    Platform: i386 (WOW64)
    Version: Windows 7
    Host system: Linux
    Host version: 5.4.0-150-generic



Now, the optimization stuff (including squared vector verbs) seem rather intriguing. With how cog-logic heavy JKGR is, any optimization is welcome. Which makes me wonder, is there anything that can be done to the renderer to optimize game performance? I remember seeing it mentioned somewhere that the renderer redraws every triangle on screen every frame, which is why higher poly models cause JK to suffer so much more in performance compared to any engine a bit more modern.
JKGR
2023-12-07, 7:32 PM #89
It's crashing in SetCameraZoom. Looks like I made a mistake in rev026. This rev027b should fix it:
https://drive.google.com/file/d/1Zpc5ldF9jXDoOkS8pIqPSgCQ2KP2VlS3/view

JK's renderer has to redraw everything every frame. The engine was made before hardware transform existed. There's nothing to be done about that. The whole renderer would have to be remade (and migrated to a newer version of DirectX that provides hardware transform functionality and that modern Windows still supports hardware transform on, so even though DX7 has hardware TnL, pretty sure modern Windows handicaps DX7 by emulating its hardware TnL, so maybe DX9?), possibly with a different 3D format, animation format, and probably countless other things.

None of that would really help a COG-heavy project for JK which is... probably mostly bottlenecked by float to int conversions... but at least generally bottlenecked by the COG stack machine performance and game logic being highly serial.

QM
2023-12-07, 8:11 PM #90
Nope. Maybe this time it's crashing for a different reason though. I tried commenting every instance of SetCameraZoom but it still crashed.

Code:
Unhandled exception: page fault on write access to 0x004e2831 in 32-bit code (0x004e2989).
Register dump:
 CS:0023 SS:002b DS:002b ES:002b FS:0063 GS:006b
 EIP:004e2989 ESP:009ffcd4 EBP:00000003 EFLAGS:00010202(  R- --  I   - - - )
 EAX:20c4835d EBX:00000001 ECX:004e2399 EDX:004e2399
 ESI:0f5aa894 EDI:00000003
Stack dump:
0x009ffcd4:  00000003 0f5aa894 00000003 00000001
0x009ffce4:  00000003 00000058 100d36b0 004e2399
0x009ffcf4:  009ffcf8 0f5aa894 0f5aa894 004e2375
0x009ffd04:  004e2399 0f5aa894 00000004 0f5aa894
0x009ffd14:  00000003 0000000d 00000003 0000823e
0x009ffd24:  00000000 00000000 00000001 00000454
Backtrace:
=>0 0x004e2989 in jk23 (+0xe2989) (0x00000003)
0x004e2989 jk23+0xe2989: movl	%eax,0x498(%ecx)
Modules:
Module	Address			Debug info	Name (130 modules)
PE	00370000-00385000	Deferred        portable
PE	00390000-003ab000	Deferred        winmm
PE	003b0000-003c6000	Deferred        smackw32
PE	00400000-008f4000	Export          jk23
PE	00d00000-01ed5000	Deferred        wined3d
PE	01ee0000-022cf000	Deferred        ole32
PE	022d0000-026a7000	Deferred        comctl32
PE	038b0000-03a15000	Deferred        winmm
PE	04be0000-04bf2000	Deferred        a3d
PE	04e00000-04e97000	Deferred        mmdevapi
PE	04ea0000-04f12000	Deferred        winepulse
PE	05040000-050ee000	Deferred        dinput8
PE	10000000-1010a000	Deferred        jk
PE	5e080000-5e0bb000	Deferred        dplayx
PE	62500000-6287c000	Deferred        oleaut32
ELF	63431000-64a80000	Deferred        iris_dri.so
PE	64a80000-64acc000	Deferred        win32u
PE	65480000-65662000	Deferred        rpcrt4
PE	65680000-65875000	Deferred        msvcrt
PE	66080000-660d5000	Deferred        msacm32
PE	66640000-6665a000	Deferred        version
PE	67500000-67544000	Deferred        imm32
PE	67c00000-67d83000	Deferred        dsound
PE	684c0000-685f0000	Deferred        combase
PE	68880000-68cfa000	Deferred        user32
PE	69840000-6990e000	Deferred        advapi32
PE	69ec0000-69ec6000	Deferred        ddraw
PE	6aac0000-6ad06000	Deferred        ucrtbase
PE	6aec0000-6b060000	Deferred        setupapi
PE	6b3c0000-6b405000	Deferred        libvorbisfile-3
PE	6bb40000-6bbbd000	Deferred        winex11
PE	6bbc0000-6bc4b000	Deferred        sechost
PE	6da80000-6dc21000	Deferred        gdi32
PE	6de80000-6df20000	Deferred        dinput
PE	71080000-710a4000	Deferred        hid
ELF	72fdf000-73aec000	Deferred        libnvidia-glvkspirv.so.440.64
ELF	73aec000-73f9d000	Deferred        libvulkan_lvp.so
ELF	73f9d000-746f7000	Deferred        libvulkan_intel.so
ELF	746f7000-78bec000	Deferred        libllvm-10.so.1
ELF	78bec000-7a800000	Deferred        libnvidia-glcore.so.440.64
PE	7a800000-7ab6c000	Deferred        opengl32
PE	7b000000-7b479000	Deferred        kernelbase
PE	7b600000-7b72c000	Deferred        kernel32
PE	7bc00000-7be4c000	Deferred        ntdll
ELF	7bee3000-7bf00000	Deferred        libxcb-glx.so.0
ELF	7c303000-7c30d000	Deferred        libdrm_nouveau.so.2
ELF	7c30d000-7c31b000	Deferred        libdrm_radeon.so.1
ELF	7c31b000-7c343000	Deferred        libglapi.so.0
ELF	7c343000-7c3ba000	Deferred        libglx_mesa.so.0
ELF	7c3ba000-7c3f5000	Deferred        libglx.so.0
ELF	7c972000-7cf18000	Deferred        libvulkan_radeon.so
ELF	7cf18000-7d000000	Deferred        libglx_nvidia.so.0
ELF	7d000000-7d004000	Deferred        <wine-loader>
ELF	7d009000-7d019000	Deferred        libsensors.so.4
ELF	7d019000-7d094000	Deferred        libgldispatch.so.0
ELF	7d094000-7d100000	Deferred        libgl.so.1
ELF	7d404000-7d408000	Deferred        libxcb-shm.so.0
ELF	7d408000-7d40c000	Deferred        libxdamage.so.1
ELF	7d40c000-7d412000	Deferred        libxcb-dri2.so.0
ELF	7d55a000-7d5d9000	Deferred        libzstd.so.1
ELF	7d5d9000-7d5ee000	Deferred        libdrm.so.2
ELF	7d5ee000-7d5f6000	Deferred        libxcb-sync.so.1
ELF	7d616000-7d634000	Deferred        libelf.so.1
ELF	7d634000-7d648000	Deferred        libnss_files.so.2
ELF	7d648000-7d663000	Deferred        libnsl.so.1
ELF	7d663000-7d671000	Deferred        libnss_nis.so.2
ELF	7d771000-7d7a8000	Deferred        libedit.so.2
ELF	7d7ab000-7d7b2000	Deferred        libvklayer_mesa_device_select.so
ELF	7d7b2000-7d7c4000	Deferred        libxcb-randr.so.0
ELF	7d7c4000-7d7d2000	Deferred        libwayland-client.so.0
ELF	7d84f000-7d867000	Deferred        libgpg-error.so.0
ELF	7d867000-7d87f000	Deferred        libresolv.so.2
ELF	7d87f000-7d90b000	Deferred        libvorbisenc.so.2
ELF	7d90b000-7d936000	Deferred        libvorbis.so.0
ELF	7d936000-7d998000	Deferred        libflac.so.8
ELF	7d998000-7da79000	Deferred        libgcrypt.so.20
ELF	7da79000-7da8f000	Deferred        liblz4.so.1
ELF	7da8f000-7daba000	Deferred        liblzma.so.5
ELF	7daba000-7db49000	Deferred        libsndfile.so.1
ELF	7db49000-7dbd9000	Deferred        libsystemd.so.0
ELF	7dbd9000-7dc34000	Deferred        libdbus-1.so.3
ELF	7dc34000-7dcc1000	Deferred        libpulsecommon-11.1.so
ELF	7dcc1000-7dd1b000	Deferred        libpulse.so.0
ELF	7de2d000-7de37000	Deferred        libnss_compat.so.2
ELF	7de3a000-7de3e000	Deferred        libxcb-present.so.0
ELF	7de3e000-7de62000	Deferred        libtinfo.so.5
ELF	7de62000-7de6b000	Deferred        libffi.so.6
ELF	7de6b000-7de72000	Deferred        libatomic.so.1
ELF	7de72000-7de9c000	Deferred        libgcc_s.so.1
ELF	7e107000-7e10a000	Deferred        libxshmfence.so.1
ELF	7e10a000-7e10f000	Deferred        libxcb-dri3.so.0
ELF	7e120000-7e132000	Deferred        libapparmor.so.1
ELF	7e1b3000-7e1bc000	Deferred        libogg.so.0
ELF	7e1bc000-7e1c7000	Deferred        libwrap.so.0
ELF	7e250000-7e25c000	Deferred        libdrm_amdgpu.so.1
ELF	7e25d000-7e262000	Deferred        libnvidia-tls.so.440.64
ELF	7e264000-7e26b000	Deferred        libasyncns.so.0
ELF	7e26b000-7e27e000	Deferred        winepulse.so
ELF	7e3f7000-7e456000	Deferred        libvulkan.so.1
ELF	7e456000-7e469000	Deferred        libxi.so.6
ELF	7e469000-7e46d000	Deferred        libxcomposite.so.1
ELF	7e46d000-7e47a000	Deferred        libxrandr.so.2
ELF	7e47a000-7e486000	Deferred        libxrender.so.1
ELF	7e486000-7e48d000	Deferred        libxxf86vm.so.1
ELF	7e48d000-7e491000	Deferred        libxinerama.so.1
ELF	7e491000-7e49b000	Deferred        librt.so.1
ELF	7e49b000-7e4b6000	Deferred        libbsd.so.0
ELF	7e4b6000-7e4bd000	Deferred        libxdmcp.so.6
ELF	7e4bd000-7e4c2000	Deferred        libxau.so.6
ELF	7e4c2000-7e4ee000	Deferred        libxcb.so.1
ELF	7e4ee000-7e638000	Deferred        libx11.so.6
ELF	7e638000-7e64d000	Deferred        libxext.so.6
ELF	7e64e000-7e651000	Deferred        libx11-xcb.so.1
ELF	7e66d000-7e674000	Deferred        libxfixes.so.3
ELF	7e674000-7e680000	Deferred        libxcursor.so.1
ELF	7e680000-7e70a000	Deferred        winex11.so
ELF	7e70a000-7e7aa000	Deferred        opengl32.so
ELF	7e83d000-7e86f000	Deferred        libexpat.so.1
ELF	7e86f000-7e8ba000	Deferred        libfontconfig.so.1
ELF	7e8ba000-7e8d9000	Deferred        libz.so.1
ELF	7e8d9000-7e913000	Deferred        libpng16.so.16
ELF	7e913000-7e9d0000	Deferred        libfreetype.so.6
ELF	7e9d0000-7ead2000	Deferred        libm.so.6
ELF	7eb05000-7ec78000	Deferred        win32u.so
ELF	7ec78000-7ee00000	Dwarf           libwine.so.1
ELF	f7c75000-f7d2c000	Deferred        ntdll.so
ELF	f7d2c000-f7f08000	Deferred        libc.so.6
ELF	f7f08000-f7f0d000	Deferred        libdl.so.2
ELF	f7f0d000-f7f2d000	Deferred        libpthread.so.0
ELF	f7f62000-f7f8a000	Deferred        ld-linux.so.2
Threads:
process  tid      prio    name (all IDs are in hex)
00000020 jkgr.exe
	00000024    0     
00000038 services.exe
	0000003c    0     
	00000040    0     wine_rpcrt4_server
	00000054    0     wine_rpcrt4_io
	0000007c    0     wine_rpcrt4_io
	00000090    0     wine_rpcrt4_io
	000000a4    0     wine_rpcrt4_io
	000000cc    0     wine_rpcrt4_io
	000000d8    0     wine_rpcrt4_io
	00000108    0     wine_rpcrt4_io
	00000128    0     wine_rpcrt4_io
00000044 AppleMobileDeviceService.exe
	00000048    0     
	0000005c    0     
	00000064    0     
	0000006c    0     
	00000070    0     
	000000c4    0     
	000000c8    0     
	00000150    0     
	00000174    0     
0000004c explorer.exe
	00000050    0     
	000000f4    0     
	000000fc    0     
	00000100    0     wine_rpcrt4_server
00000074 mDNSResponder.exe
	00000078    0     
	00000080    0     
	00000084    0     wine_sechost_service
00000088 svchost.exe
	0000008c    0     
	00000094    0     
	00000098    0     wine_sechost_service
0000009c winedevice.exe
	000000a0    0     
	000000a8    0     
	000000ac    0     wine_sechost_service
	000000b0    0     
	000000b4    0     
	000000b8    0     
	0000011c    0     
000000bc winedevice.exe
	000000c0    0     
	000000d0    0     
	000000d4    0     wine_sechost_service
	000000dc    0     
	000000e0    0     
	000000e4    0     
	000000f0    0     
	000000f8    0     
000000e8 plugplay.exe
	000000ec    0     
	00000110    0     
	00000114    0     wine_sechost_service
	00000118    0     wine_rpcrt4_server
00000120 rpcss.exe
	00000124    0     
	0000012c    0     
	00000130    0     wine_sechost_service
	00000134    0     wine_rpcrt4_server
	00000138    0     wine_rpcrt4_server
	0000013c    0     wine_rpcrt4_io
00000144 (D) E:\JK\jk23.exe
	00000148    0 <== 
	0000014c    0     
	0000015c   15     
	00000160    0     
	00000164   15     winepulse_mainloop
	00000168   15     winepulse_timer_loop
	0000016c   15     wine_dsound_mixer
	00000178    0     
	0000017c    0     
	00000180    0     
	00000184    0     wine_mmdevapi_notification
	00000188   15     winepulse_timer_loop
	0000018c    0     wined3d_cs
System information:
    Wine build: wine-8.0.1
    Platform: i386 (WOW64)
    Version: Windows 7
    Host system: Linux
    Host version: 5.4.0-150-generic
JKGR
2023-12-07, 8:19 PM #91
That crash appears to be in VectorDistSq. Had you already put that in a COG to try out? Investigating what could make it crash. Just figured I'd ask while looking at it.

QM

Edit: Okay, fixed that too, cogext 2023 rev027c:
https://drive.google.com/file/d/1OvGpB0Pea1MSiBx8CDq9C1VlWldeu-xW/view

Really happy with the crash info Linux spits out, and that it treats Windows modules as first-class citizens for the purposes of diagnostics at least (providing module names, memory address ranges, etc.). Makes figuring these crashes out even easier than if you were using Windows.

Though I wish it gave the disassembled instruction in Intel syntax instead of the asinine AT&T syntax.
What it lists as "movl %eax,0x498(%ecx)" should be "mov [ecx + 498h], eax", were its head not up its own butt.



Edit 2: JK 2023 rev219, cogext 2023 rev028:
https://drive.google.com/file/d/13LN8r6a50QhkKny4FxhZqhyyhZWxzZND/view
https://drive.google.com/file/d/11s3aKTrnMhF9hibt6pqLJENkHyllPHGA/view

The JK patch adds support for a new COG data type I'm calling stack strings and fixes a surface save data hole I'd introduced when improving the surface network packet. Sadly this means save files are back up to slightly bigger than vanilla size (though are still vanilla compatible), but I optimized surface loading logic so load times of saves for the current level will be faster than vanilla at least.

The cogext patch adds temporary model loading support to GetModelMesh and GetModelNode, which lets you look up model mesh and node numbers, by name, in a not actually loaded model to then also use with temp model loading SetMesh verbs. It's all slow, but the point is to preserve loaded model slots.

Also two bit manipulation verbs:
- BitShift(int, amount); returns int shifted left (larger) if positive amount and shifted right (smaller) if negative amount
- BitRotate(int, amount); returns int rotated left if positive amount and rotated right if negative amount

And some stack string verbs:
- BuildStackString(int, int, int, int); returns a max 16 char stack string for immediate use
- EncodeVectorString(string); returns a vector containing a max 15 char string suitable for storing / transmitting; must be decoded before being used as a string
- DecodeVectorString(vector); returns a max 15 char stack string for immediate use

Stack strings can be assigned to variables but should be used immediately (not held until after a Sleep, Pulse or Timer) because they won't survive a game save / load. This is true for both direct use (on the stack) and indirect (stored in a variable).

They can be used anywhere normal strings can be used.

It should be safe to store stack strings to the COG heap (and load them), but I didn't test.

The vector returned by EncodeVectorString can be saved and used whenever, or each component managed as separate floats/flexes. They're gibberish as far as a float value goes, so don't try and do math on them.

Store a stack string on the heap or encode it as a vector for deferred use.

BuildStackString expects data in big-endian order so that it's at least somewhat human readable in COG:
Code:
SetThingMesh(player, GetThingJointMesh(player, 2),
BuildStackString(0x73322E33,0x646F0000,0x00000000,0x00000000), // "s2.3do"
BuildStackString(0x7374746F,0x72736F00,0x00000000,0x00000000));// "sttorso"


The first character must be 0x20 or greater; this basically just means don't start a stack string with a tab character.

There are currently caveats to using full 16 length stack strings that are adjacent on the stack as they effectively concatenate. This is because I intend to allow longer than 16 char stack strings but haven't worked out all the logistics yet. To avoid unexpected results, if using a verb that can use multiple string arguments in a row:
e.g. SetThingMesh(player, BuildStackString(), BuildStackString(), BuildStackString());
...make sure no two adjacent arguments are direct stack strings that are the full 16 char length; make that middle-of-the-three a variable that's holding a stack string in that circumstance:
stackstring = BuildStackString(); SetThingMesh(player, BuildStackString(), stackstring , BuildStackString());

Now, what's the point of these strings? String literals in COG (e.g. Print("test"); ) create an anonymous variable each which in an extreme case can make you hit the 256 variable (symbol) cap in a COG. Print(BuildStackString(0x74657374,0,0,0)); creates the same result, but without using a COG variable. EncodeVectorString also gives you data you can use with SendTrigger for multiplayer, or SendMessage(etc.) for local string data transmission. String transmission was my primary goal.

Due to packing each character into 6 bits, EncodeVectorString has a weakness on strings with lots of variable case. Each float, so each 5 characters, can only all be uppercase or all lowercase. "K_Rhand" gets encoded as "K_R"+"hand" which works. But "K_rHand" would be encoded as "K_"+"r"+"H"+"and" which needs 4 floats, but a vector is only 3, so if you tried Print(DecodeVectorString(EncodeVectorString("K_rHand"))); you'd get "K_rH" as output.

The encoding is:
Code:
abcccccc ddddddee eeeeffff ffgggggg
a : 0 = uppercase, 1 = lowercase
b : 0 = 5 char binary, 1 = 4 char integer
cccccc = char0
dddddd = char1
eeeeee = char2
ffffff = char3
gggggg = char4


Each char is:
Code:
 0x00 = 0x00 \0 nul
 0x20 = 0x20 ' ' space
 0x09 = 0x20 tab becomes space
 0x5F = 0x5F '_' underscore

 0x3C = 0x3C '<' (uppercase only)
 0x3E = 0x3E '>' (uppercase only)
 0x40 = 0x3C '@' (lowercase only)
 0x60 = 0x3E '`' (lowercase only)

=0x00 = val
=0x20 = val
=0x5F = val - 0x20
<0x41 = val - 0x20
<0x61 = val - 0x20 (uppercase only)
<0x7F = val - 0x40 (lowercase only)

Underscore and space get special treatment to be case-insensitive, @ and ` are moved for space.
Otherwise it's basically ascii char value -0x20 for most, and an extra -0x20 for lowercase letters and {|}~.

Remaining values below 0x20 and 0x7F or above become 0x3F - 0x20 '?'


The 4 char integer encoding is a separate COG manipulatable format that limits you to fewer characters, but can be directly parsed by COG logic.



Edit 3: JK 2023 rev220:
https://drive.google.com/file/d/1kXNKAiWkncITN4EvDWmuUmEuYixZSVkv/view

Rewrote some of the logic that adds the glow-in-the-dark pixels to textures in 32-bit rendering mode so that it works on levels of higher geometric complexity. Before, if a render was too complex (too many polygons) only some surfaces would get glowy pixels for the current frame. Drazen Isle and Gromas Mines 2 come to mind.

This might be the last update this year. Got a lot done! (not like, this update, but this year, in total)
I didn't count, but it must be more than 100 new COG verbs, some more JK bugs fixed, little performance enhancements here and there, and rendering improvements.



Edit 4: Okay, one last update for 2023, JK 2023 rev221:
https://drive.google.com/file/d/1f6TAi06Sge5h1B5ubUCwHvB1HFegqmJX/view

Bumped the internal version numbers to 2023.12.09 (they were still the 2022 related values). No functional changes other than a tweak to the -? command line argument to accommodate the version number changes.
2024-01-02, 3:56 AM #92
I'd almost forgotten this patch initially started as tweaks to the renderer, including the glow-in-the-dark bits! That was way back in 2018, I think? Now, regarding what's to come, way back in 2022 you mentioned making tweaks to JkGfxMod, how are these going, if at all?


Now, thank you greatly for your service and contributions to up and coming (?) JK modding! ���� There are so many things I've implemented in JkGR recently that wouldn't be possible without your patches, so I'm deeply thankful. Have a happy new year!


Edit: I forgot to mention, but something in your patches seems to have fixed a long standing issue I had with JKGR crashing seemingly at random after around 30mins in the same level. Maybe it had something to do with those camera memory leaks you mentioned earlier?
JKGR
123

↑ Up to the top!