[CSS] Setting weapon view models.
Posted: Mon Dec 01, 2014 7:20 pm
I've been trying to set weapon view models using this topic https://forums.alliedmods.net/showthread.php?t=244926 as a guideline.
The way the code in that topic achieves custom weapon models nearly perfectly is by binding the custom model to a second possible view model index, which appears to stay unused by default and copying m_nSequence, m_flPlaybackRate and m_nSequence over from the default model, then hiding the default model and drawing the secondary model, I tested this with the provided SM plugin and it works almost flawlessly.
Now, I've basically tried to convert the plugin from SM to SourcePython. I implemented it as good as I could in SourcePython (while staying relatively close and not doing Pythonic optimisations so I could more easily compare and not lose track), but basically no dice. I end up with my knife model being invisible.
But I was able to semi-reliably glitch the model to stick to my glock when spawning and weapon switching (glock-knife-glock), and upon toggling between burst fire and semi I was able to get the custom model's animations fully working on the glock when I each time toggled between firemodes.
So I'm getting the feeling that I'm close. At this point some help would really be appreciated. Here is my best working code:
Side note: All in all I was at the very least very happy that the server wasn't laggy at all. Which IMO was quite a testament to how solid SourcePython is over EventScripts (I should do a performance comparison one day).
The way the code in that topic achieves custom weapon models nearly perfectly is by binding the custom model to a second possible view model index, which appears to stay unused by default and copying m_nSequence, m_flPlaybackRate and m_nSequence over from the default model, then hiding the default model and drawing the secondary model, I tested this with the provided SM plugin and it works almost flawlessly.
Now, I've basically tried to convert the plugin from SM to SourcePython. I implemented it as good as I could in SourcePython (while staying relatively close and not doing Pythonic optimisations so I could more easily compare and not lose track), but basically no dice. I end up with my knife model being invisible.
But I was able to semi-reliably glitch the model to stick to my glock when spawning and weapon switching (glock-knife-glock), and upon toggling between burst fire and semi I was able to get the custom model's animations fully working on the glock when I each time toggled between firemodes.
So I'm getting the feeling that I'm close. At this point some help would really be appreciated. Here is my best working code:
Syntax: Select all
import memory
from memory.manager import manager
from memory.manager import CustomType
from memory.manager import Argument
from memory.manager import Return
from filters.players import PlayerIter
from filters.entities import EntityIter
from players.helpers import index_from_pointer, index_from_userid
from entities.helpers import pointer_from_inthandle, edict_from_index, index_from_inthandle
from players.entity import PlayerEntity
from entities.entity import BaseEntity
from events import Event
from tools import server_tools
from core import PLATFORM
from engines.precache import Model
from stringtables.downloads import Downloadables
model = Model('models/weapons/franug_cwi/knuckles/v_knuckles.mdl')
dl = Downloadables()
dl.add("models/weapons/franug_cwi/knuckles")
dl.add("materials/models/weapons/v_models/brass_knuckles")
EF_NODRAW = (1 << 5)
just_spawned = set()
ClientVM = (dict(), dict())
model_overrides = dict()
is_custom = dict()
old_weapon_index = dict()
old_sequence = dict()
old_cycle = dict()
Weapon_CanUse = None
PreThink = None
PostThink = None
Spawn = None
class CBaseEntity(CustomType, metaclass=manager):
Spawn = manager.virtual_function(
22 if PLATFORM == 'windows' else 23,
(),
Return.VOID
)
@property
def base_entity(self):
return BaseEntity(index_from_pointer(self))
class CCSPlayer(CustomType, metaclass=manager):
PreThink = manager.virtual_function(
331 if PLATFORM == 'windows' else 332,
(),
Return.VOID
)
PostThink = manager.virtual_function(
332 if PLATFORM == 'windows' else 333,
(),
Return.VOID
)
@property
def player_entity(self):
return PlayerEntity(index_from_pointer(self))
def set_weapon_model(weapon_index, model_index):
weapon = BaseEntity(weapon_index)
player = PlayerEntity(index_from_inthandle(weapon.m_hOwner))
classname = weapon.classname
# player.drop_weapon(weapon.pointer, True, True)
# weapon.Kill()
server_tools.remove_entity_immediate(weapon_index)
player.give_named_item(classname, 0)
for weapon_index in player.weapon_indexes(is_filters='knife'): break
model_overrides[weapon_index] = model_index
def load():
for_players_already_on()
hook_all()
for_players_already_on()
def unload():
unhook_all()
@Event
def player_activate(event):
hook_all()
@Event
def player_death(event):
ClientVM[1][PlayerEntity(index_from_userid(event.get_int("userid"))).inthandle].m_fEffects |= EF_NODRAW # += EF_NODRAW
@Event
def player_spawn(event):
player = PlayerEntity(index_from_userid(event.get_int("userid")))
just_spawned.add(player.inthandle)
for weapon_index in player.weapon_indexes(is_filters='knife'):
print("Setting Knife", weapon_index, "to", model.index, model)
set_weapon_model(weapon_index, model.index)
def for_players_already_on():
for index in PlayerIter(return_types='index'):
player_entity = PlayerEntity(index)
ClientVM[0][player_entity.inthandle] = BaseEntity(index_from_inthandle(player_entity.m_hViewModel))
for index2 in EntityIter("predicted_viewmodel", True, "index"):
be = BaseEntity(index2)
if be.m_hOwner == player_entity.inthandle:
if be.m_nViewModelIndex == 1:
ClientVM[1][player_entity.inthandle] = be
break
def hook_all():
global Weapon_CanUse, PreThink, PostThink, Spawn
if PostThink is not None:
return
#CBaseEntity
for pointer in EntityIter("predicted_viewmodel", True, "pointer"): break
try:
entity = memory.make_object(CBaseEntity, pointer)
except UnboundLocalError:
print("Could not hook on entity")
else:
entity.Spawn.add_post_hook(post_spawn)
Spawn = entity.Spawn
#CCSPlayer
players = tuple(PlayerIter(return_types='pointer'))
if not players:
return
player = memory.make_object(CCSPlayer, players[0])
# player.PreThink.add_post_hook(post_prethink)
player.PostThink.add_post_hook(post_postthink)
# PreThink = player.PreThink
PostThink = player.PostThink
def unhook_all():
if PostThink is not None:
# PreThink.remove_post_hook(post_prethink)
PostThink.remove_post_hook(post_postthink)
if Spawn is not None:
Spawn.remove_post_hook(post_spawn)
def post_spawn(args, return_value):
entity = memory.make_object(CBaseEntity, args[0])
owner = entity.base_entity.m_hOwner
if owner:
index = entity.base_entity.index
viewmodel = entity.base_entity.m_nViewModelIndex
ClientVM[viewmodel][owner] = BaseEntity(index)
def post_prethink(args, return_value):
player = memory.make_object(CCSPlayer, args[0])
def post_postthink(args, return_value):
player = memory.make_object(CCSPlayer, args[0])
if not player.player_entity.isdead:
player_handle = player.player_entity.inthandle
try:
weapon_index = index_from_inthandle(player.player_entity.active_weapon)
old_weapon_index[player_handle]
except (ValueError, KeyError):
weapon_index = -1
sequence = ClientVM[0][player_handle].m_nSequence
cycle = ClientVM[0][player_handle].m_flCycle
if weapon_index <= 0:
ClientVM[1][player_handle].m_fEffects |= EF_NODRAW # += EF_NODRAW
is_custom[player_handle] = False
else:
if weapon_index != old_weapon_index[player_handle]:
try:
custom_model_index = model_overrides[weapon_index]
except KeyError:
ClientVM[1][player_handle].m_fEffects |= EF_NODRAW # += EF_NODRAW
is_custom[player_handle] = False
else:
ClientVM[0][player_handle].m_fEffects |= EF_NODRAW # += EF_NODRAW
ClientVM[1][player_handle].m_fEffects &= ~EF_NODRAW # -= EF_NODRAW
ClientVM[1][player_handle].m_nModelIndex = custom_model_index
ClientVM[1][player_handle].m_hWeapon = ClientVM[0][player_handle].m_hWeapon
ClientVM[1][player_handle].m_nSequence = ClientVM[0][player_handle].m_nSequence
ClientVM[1][player_handle].m_flPlaybackRate = ClientVM[0][player_handle].m_flPlaybackRate
is_custom[player_handle] = True
else:
try:
custom = is_custom[player_handle]
except KeyError:
pass
else:
if custom:
ClientVM[1][player_handle].m_nSequence = ClientVM[0][player_handle].m_nSequence
ClientVM[1][player_handle].m_flPlaybackRate = ClientVM[0][player_handle].m_flPlaybackRate
if cycle < old_cycle[player_handle] and sequence == old_sequence[player_handle]:
ClientVM[1][player_handle].m_nSequence = 0
try:
just_spawned.remove(player_handle)
except KeyError:
pass
else:
try:
custom = is_custom[player_handle]
except KeyError:
pass
else:
if custom:
ClientVM[0][player_handle].m_fEffects |= EF_NODRAW # += EF_NODRAW
old_weapon_index[player_handle] = weapon_index
old_sequence[player_handle] = sequence
old_cycle[player_handle] = cycle
# print("postthink", args[0], weapon_index, sequence, cycle, player.player_entity.name)
Side note: All in all I was at the very least very happy that the server wasn't laggy at all. Which IMO was quite a testament to how solid SourcePython is over EventScripts (I should do a performance comparison one day).