fallback_dir "bshift"
This will let you use Blue Shift content in your mod.
The mouse input issues are a known bug in the SDK code. There is a fix available as a pull request but Valve never merged it.
fallback_dir "bshift"
UTIL_SetOrigin
when changing an entity's origin, unless the origin variable is being used for storage (some entities do this, but it's a bad idea).StudioFrameAdvance
will trickle down into movement update logic which applies the animation movement to the NPC so the origin variable will be updated.pev->angles
should work regardless though. Make sure nothing is resetting the angles elsewhere.[12:56:00] [Server thread/DEBUG] [cofhcore/]: RetroGening [-3, 34].
should be showing up.//In player.cpp
int gmsgMyMsg = 0;
//In LinkUserMessages
//Maximum name length is 12 bytes
//Sending a string, so variable length message (-1)
//Maximum message size is 192 bytes
gmsgMyMsg = REG_USER_MSG( "MyMsg", -1 );
//In hud.h
int _cdecl MsgFunc_MyMsg(const char *pszName, int iSize, void *pbuf);
//In hud.cpp
int __MsgFunc_MyMsg(const char *pszName, int iSize, void *pbuf)
{
return gHUD.MsgFunc_MyMsg(pszName, iSize, pbuf );
}
//In CHud::Init
HOOK_MESSAGE( MyMsg );
//In hud_msg.cpp
int CHud:: MsgFunc_MyMsg( const char *pszName, int iSize, void *pbuf )
{
BEGIN_READ( pbuf, iSize );
CenterPrint( READ_STRING() );
return 1;
}
This is just for a message in CHud, it's a bit different for a message in another Hud element.extern int gmsgMyMsg;
MESSAGE_BEGIN( MSG_ALL, gmsgTextMsg );
WRITE_STRING( "my message" );
MESSAGE_END();
Assuming you're sending it to all clients reliably.package SharpLife.Game.Networking.Messages;
message MyMsg
{
string text = 1;
}
Receiving it in code:
public class SomeClass : IMessageReceiveHandler<MyMsg>
{
public SomeClass(MessagesReceiveHandler handler)
{
handler.RegisterHandler(this);
}
public void ReceiveMessage(NetConnection connection, MyMsg message)
{
//-1 means centered for an axis
_graphics.Text.DrawText(message.Text, -1, -1);
}
}
And using it:
Context.Messages.SendMessage(new MyMsg{ Text = "my message" });
And now the Unity approach:
//Singleton component on some entity used to communicate from server to client for the hud
public class HudText : Component
{
[ClientRpc]
public void CenterPrint(string message)
{
_graphics.Text.DrawText(message, -1, -1);
}
}
//Some other code in some other component
World.Instance.Hud.CenterPrint("my message");
Where World
is a component used to identify the game world, placed on the entity that represents the world, that has a property public HudText Hud { get; }
.Update
on every component:
foreach (var entity in _entities)
{
entity.Update();
}
//Entity's Update method
void Update()
{
foreach (var component in _components)
{
component.Update();
}
}
Not every component actually overrides Update
but the cost of the call still exists.//Entity's Update method
void Update()
{
foreach (var component in _components)
{
component._metaData.Update.Delegate?.Invoke(component);
}
}
So now instead of a virtual method call it's a delegate invocation, but only if the delegate exists. The delegate is created when the component type is first used, as metadata that's generated once and then stored in each instance's _metaData
field. This reduces the overhead, and since components rarely implement these methods (Update is called every game frame, hardly ever needed in Half-Life) it means the overhead involved in managing components is reduced.foreach (var component in _activeComponents)
{
component._metaData.Update.Delegate?.Invoke(component);
}
Instead of calling the entity's Update
method and letting that handle the updating of the components, all active components can be put into a single list and updated in one go by the game every frame. This eliminates the overhead involved with calling Entity.Update
and iterating over each individual list so often.I am still running XP and never have had any virus warnings... You must only have to keep you antivirus updated and never visit "extrange" or suspicious web sites. The same Win XP SP3 since 2009 without being reinstalled!! XDAnti virus software can't protect against exploits in the OS itself. You're essentially claiming that closing the door and leaving it unlocked is enough to stop burglars. You can be compromised and not know it.
for each entity in entity_list do
entity.think()
A component based system works like this:
for each entity in entity_list do
for each component in entity do
component.think()
An ECS works like this:
for each system in system_list do
system.update()
There are far fewer systems than there are entities, and there are far fewer entities than there are components.for each entity in entity_list do
if entity is not world and entity is not player
entity.move()
entity.think()
The world never moves or thinks, and players are handled elsewhere.for each entity in entity_list do
if entity is not world and entity is not player
entity.move()
for each system in system_list do
system.update()
The result is that instead of executing each entity's think method after the last, all component systems think after all entities have moved. This is more correct than what GoldSource does, but it will change game behavior slightly in these cases where order of execution mattered.MAKE_STRING( ALLOC_STRING( pszName ) )
to make sure it'll work, but if this code runs often you'll end up running out of memory in the engine since each ALLOC_STRING call allocates more memory.and i also trying to say, trigger changelevels arent working in singleplayer maps when playing MP, are they?They're disabled for multiplayer, but it's easy to re-enable them. The hardest part about seamless transitions in the vanilla engine is that it wasn't designed for multiplayer use, so save games don't handle it. Also a fair amount of code in the SDK assumes the first player is in charge of gameplay, so things can break in weird ways. Easy to fix if you know what you're doing though.
i was thinking hl's coop mode is broken. i didnt know it wasntHalf-Life itself doesn't have co-op at all, beyond an
IsCoOp
member in gamerules that's only used to find info_player_coop
spawn points. Valve didn't finish it in time for Half-Life, but Op4 does seem to have it. Which brings me to: https://twhl.info/thread/view/19673int teamCount[ MaxTeams ] = {};
for( auto pPlayer : UTIL_FindPlayers() )
{
if( pPlayer->m_iTeamNum != CTFTeam::None )
{
++teamCount[ ( ( int ) pPlayer->m_iTeamNum ) - 1 ];
}
}
I'm also using enum class, as you can see here. It keeps things cleaner and adds type checking, though it does have some drawbacks.auto useDefault = true;
for( auto pEquip : UTIL_FindEntitiesByClassname( "game_player_equip" ) )
{
useDefault = false;
pEquip->Touch( pPlayer );
}
It's basically the same as before, but it's easier to use and you can't screw up the logic, like off by one errors in player iteration or a forgotten null check. It's also type safe if you need a specific class:
for( auto pFlag : UTIL_FindEntitiesByClassname<CTFGoalFlag>( "item_ctfflag" ) )
{
if( pFlag->m_iGoalState == 2 )
{
pFlag->TurnOnLight( pPlayer );
}
}
(Not all of the constants have been defined yet)auto pPlayer = GET_PRIVATE<CBasePlayer>( pItem->pev->owner );
auto pOtherPlayer = CBaseEntity::Instance<CBasePlayer>( tr.pHit );
auto pFlag = pPlayer->m_pFlag.Entity<CTFGoalFlag>();
This eliminates the casts used otherwise, and also allows you to swap out the static_cast
with a dynamic_cast
to help find incorrect casts.What are the entities did you tested successfully among, info_player entities, env entities, lights (I saw something about those), scripst,etc.? apart from what´s descibed in Post #339709.That's the prototype for SharpLife, which ran under the original engine and only implemented game logic. It was essentially a converted SDK, but i scrapped it in favor of a complete rebuild, so just ignore all that.
Also, what programs are you using to edit-compile the source?Visual Studio 2017 with C#7.3. The native wrapper uses C++17, but you'll probably never touch it since it's very simple and only does one thing.
Sorry for saying the "translation" thing, but, in your experience, what will be the major problems a non expert code will find when trying to "port" his/her code to SL?, many of us use tutorials all written in C++...No problems really, you'll just have to know which pev members map to which members in the new version. That's not really hard to figure out.
Sorry for my too basic questions, I know that maybe this is not the place to ask them because the info here reached a high level, but I am very interested in SL as I was in EHL and PS before, and I want to gather as much info as possible before making the decission to jump from C++ to C#, because if C++ was sometimes like chinese to me, I think I will not be able to learn korean.You shouldn't make any decisions yet, this project is far from complete. I'd suggest checking out tutorials for basic Hello World stuff first, then maybe WPF since it requires the use of many language features.
btw can we make another thread for SL v2 for not to forget cool ideas. and not to flood this thread with weird ideas.That's probably years away at this point, so i wouldn't bother just yet.
cause i have one more idea to implement: unbroken coop mode and seamless level transition in multiplayer server.I was already going to implement co-op (Opposing Force has a co-op gamemode in it), what do you mean by unbroken?
You caught me!! But, If it can load original content like the original HL does I will wait for sure. Also It appears to work without vgui.dll, which´s the major limitation of Xash when it comes to go greenlightened on STEAM, right? , I´m with ZWC for the last 14 years, one more will not harm me.The original engine references vgui.dll, but my code doesn't use it.
In what a media playing is about, can we use other formats than AVI for the intro and sierra videos? also, I remember that in EHL you wanted to add background maps for the game menus, is this still present in SL?The original engine can't play any videos, and SharpLife can't do it either. I'm not going to look into that any time soon either.
UTIL_LogPrintf(
"\"%s<%i><%u><spectator>\" joined team \"spectator\"\n",
STRING( pPlayer->pev->netname ),
g_engfuncs.pfnGetPlayerUserId( pPlayer->edict() ),
g_engfuncs.pfnGetPlayerWONId( pPlayer->edict() ) );
The equivalent in SharpLife would be:
_logger.Information( "\"{PlayerName}<{UserId}><{SteamId}><spectator>\" joined team \"spectator\"", player.PlayerName, player.UserId, player.SteamId );
Changing WONId to SteamId since WONId is always -1 now.sprintf( text, "* you are on team '%s'\n", team_names[ ( int ) pPlayer->m_iTeamNum - 1 ] );
var text = $"* you are on team '{TeamNames[(int) player.TeamNumber]}'\n";
No possibility of buffer overflows here.CTFGoalFlag pFlag = ( CTFGoalFlag* ) ( CBaseEntity* ) pPlayer->m_pFlag;
if( pFlag )
{
pFlag->ReturnFlag();
}
Becomes:
EntityList.GetEntity<CTFGoalFlag>(player.Flag)?.ReturnFlag();
You don't have to do the double cast anymore (needed since EHANDLE can only be cast to CBaseEntity through its conversion operator), and the cast is safe instead of potentially creating an invalid object that can crash the game when used. Use of ?
here is the same as the if check, if the object is not null call this method.edict_t* pKiller = INDEXENT( 0 );
entvars_t* pEntKiller = pKiller ? &pKiller->v : nullptr;
None of that is needed in SharpLife, you can just use BaseEntity directly:
var killer = EntityList.GetEntityByIndex( 0 );
Since this just gets the world you can also get it through Context.Entities.World
.pPlayer->pev->effects |= EF_NODRAW;
pPlayer->pev->flags |= FL_SPECTATOR;
pPlayer->pev->solid = SOLID_NOT;
pPlayer->pev->movetype = MOVETYPE_NOCLIP;
pPlayer->pev->takedamage = DAMAGE_NO;
pPlayer->m_iHideHUD |= HIDEHUD_HEALTH | HIDEHUD_WEAPONS;
pPlayer->m_afPhysicsFlags |= PFLAG_OBSERVER;
pPlayer->m_iNewTeamNum = CTFTeam::None;
pPlayer->m_iCurrentMenu = 0;
pPlayer->m_iTeamNum = CTFTeam::None;
player.Effects |= Effect.Nodraw;
player.Flags |= EntityFlag.Spectator;
player.Solid = Solid.Not;
player.Movetype = Movetype.Noclip;
player.Takedamage = TakeDamageMode.No;
player.HideHUD |= HideHud.Health | HideHud.Weapons;
player.PhysicsFlags |= PhysicsFlag.Observer;
player.NewTeamNumber = CTFTeam.None;
player.CurrentMenu = Menu.None;
player.TeamNum = CTFTeam.None;
Though i expect some of these variables will become obsolete since they're used for networking physics specific stuff. There's overlap here and there that can be eliminated.2019-01-10 00:34:47.640 +01:00 [ERR] A fatal error occurred
System.IO.FileNotFoundException: Could not resolve absolute path
File name: 'sprites\sewerfog.spr'
at SharpLife.FileSystem.DiskFileSystem.GetAbsolutePath(String relativePath, String pathID) in C:\Users\Sam\Documents\GitHub\SharpLife_full_dev\SharpLife-Engine\src\SharpLife.FileSystem\DiskFileSystem.cs:line 134
at SharpLife.FileSystem.DiskFileSystem.Open(String relativePath, FileMode mode, FileAccess access, FileShare share, String pathID) in C:\Users\Sam\Documents\GitHub\SharpLife_full_dev\SharpLife-Engine\src\SharpLife.FileSystem\DiskFileSystem.cs:line 222
at SharpLife.FileSystem.FileSystemExtensions.OpenRead(IFileSystem self, String relativePath, String pathID) in C:\Users\Sam\Documents\GitHub\SharpLife_full_dev\SharpLife-Engine\src\SharpLife.FileSystem\FileSystemExtensions.cs:line 254
at SharpLife.Models.ModelManager.LoadModel(String modelName) in C:\Users\Sam\Documents\GitHub\SharpLife_full_dev\SharpLife-Engine\src\SharpLife.Models\ModelManager.cs:line 65
at SharpLife.Models.ModelManager.InternalLoad(String modelName, Boolean throwOnFailure) in C:\Users\Sam\Documents\GitHub\SharpLife_full_dev\SharpLife-Engine\src\SharpLife.Models\ModelManager.cs:line 87
at SharpLife.Models.ModelManager.Load(String modelName) in C:\Users\Sam\Documents\GitHub\SharpLife_full_dev\SharpLife-Engine\src\SharpLife.Models\ModelManager.cs:line 119
at SharpLife.Engine.Server.Resources.ServerModels.LoadModel(String modelName) in C:\Users\Sam\Documents\GitHub\SharpLife_full_dev\SharpLife-Engine\src\SharpLife.Engine.Server\Resources\ServerModels.cs:line 75
at SharpLife.Game.Server.Entities.BaseEntity.KeyValue(String key, String value) in C:\Users\Sam\Documents\GitHub\SharpLife_full_dev\SharpLife-Engine\src\SharpLife.Game.Server\Entities\BaseEntity.cs:line 228
at SharpLife.Game.Server.Entities.Effects.EnvSprite.KeyValue(String key, String value) in C:\Users\Sam\Documents\GitHub\SharpLife_full_dev\SharpLife-Engine\src\SharpLife.Game.Server\Entities\Effects\EnvSprite.cs:line 45
at SharpLife.Game.Server.Entities.ServerEntities.LoadEntity(List`1 block, Int32 index) in C:\Users\Sam\Documents\GitHub\SharpLife_full_dev\SharpLife-Engine\src\SharpLife.Game.Server\Entities\ServerEntities.cs:line 267
at SharpLife.Game.Server.Entities.ServerEntities.LoadEntities(String entityData) in C:\Users\Sam\Documents\GitHub\SharpLife_full_dev\SharpLife-Engine\src\SharpLife.Game.Server\Entities\ServerEntities.cs:line 197
at SharpLife.Game.Server.Entities.ServerEntities.MapLoadBegin(ITime gameTime, IMapInfo mapInfo, GamePhysics gamePhysics, String entityData, Boolean loadGame) in C:\Users\Sam\Documents\GitHub\SharpLife_full_dev\SharpLife-Engine\src\SharpLife.Game.Server\Entities\ServerEntities.cs:line 170
at SharpLife.Game.Server.API.GameServer.MapLoadContinue(Boolean loadGame) in C:\Users\Sam\Documents\GitHub\SharpLife_full_dev\SharpLife-Engine\src\SharpLife.Game.Server\API\GameServer.cs:line 207
at SharpLife.Engine.Server.Host.EngineServerHost.InitializeMap(ServerStartFlags flags) in C:\Users\Sam\Documents\GitHub\SharpLife_full_dev\SharpLife-Engine\src\SharpLife.Engine.Server\Host\EngineServerHost.cs:line 240
at SharpLife.Engine.Engines.ClientServerEngine.FinishLoadMap(String startSpot, ServerStartFlags flags) in C:\Users\Sam\Documents\GitHub\SharpLife_full_dev\SharpLife-Engine\src\SharpLife.Engine\Engines\ClientServerEngine.cs:line 442
at SharpLife.Engine.Engines.ClientServerEngine.StartNewMap(ICommandArgs command) in C:\Users\Sam\Documents\GitHub\SharpLife_full_dev\SharpLife-Engine\src\SharpLife.Engine\Engines\ClientServerEngine.cs:line 426
at SharpLife.CommandSystem.Commands.Command.OnCommand(ICommandArgs command) in C:\Users\Sam\Documents\GitHub\SharpLife_full_dev\SharpLife-Engine\src\SharpLife.CommandSystem\Commands\Command.cs:line 43
at SharpLife.CommandSystem.CommandQueue.Execute() in C:\Users\Sam\Documents\GitHub\SharpLife_full_dev\SharpLife-Engine\src\SharpLife.CommandSystem\CommandQueue.cs:line 95
at SharpLife.CommandSystem.CommandSystem.Execute() in C:\Users\Sam\Documents\GitHub\SharpLife_full_dev\SharpLife-Engine\src\SharpLife.CommandSystem\CommandSystem.cs:line 103
at SharpLife.Engine.Engines.ClientServerEngine.Update(Single deltaSeconds) in C:\Users\Sam\Documents\GitHub\SharpLife_full_dev\SharpLife-Engine\src\SharpLife.Engine\Engines\ClientServerEngine.cs:line 196
at SharpLife.Engine.Engines.ClientServerEngine.Run(String[] args, HostType hostType) in C:\Users\Sam\Documents\GitHub\SharpLife_full_dev\SharpLife-Engine\src\SharpLife.Engine\Engines\ClientServerEngine.cs:line 181
at SharpLife.Engine.Host.EngineHost.Start(String[] args, HostType type) in C:\Users\Sam\Documents\GitHub\SharpLife_full_dev\SharpLife-Engine\src\SharpLife.Engine\Host\EngineHost.cs:line 36
It's a bit much but you get everything you need to know.some corpses can gibbed with one hit. others are too much hits and they broke the hitting animation so without swinging the crowbar gibbing the corpses. (so politicians or media or something dont want to see a game where player constantly whacking a corpse. it seems so they removed animations.)Depending on the NPC the health for corpses is set to half the original health value, so it could be quite high sometimes. Corpses are still subject to hitgroups so that might have something to do with it if you're essentially hitting a monster's feet.
and you cant hit the corpse if that part of corpse is out of the otiginal monsters hull (bounding box)That can probably be fixed by changing the bounding box upon death to match the shape when the NPC has come to rest. That depends on how sequences store hull sizes and stuff.
if hl2 smd to hl1 mdl compiler isnt posible, at least hl2 smd file to hl1 smd file can be made. the hl2 smd file format is easy to find, i guess. and there is info about hl2 smd at valve developer site.It's possible to convert them, but information will be lost. That's why it may be better to use a new format that supports what you need before writing any converter tools.
what about 24 bit textures? ok if only v2 supports this. i cant wait to see v2V2 can support 32 bit just fine. I'm using a library made for image loading so eventually it could support any kind of image that that library supports.
and there is one more probleb about goldsrc. i dont want to use milkshape. its expensive and limited. i can use blender but its only supports hl2 smd files. so maybe you can make a compiler for hl2 smds to hl1 mdls.I've never dabbled in Source programming and from what i know about it the studiomdl compiler for it is closed source. Maybe an easier to use format could be made for it one day though.
Better use hornetgun... But the entity limit is a problem (BIG PROBLEM) as you say. How much entities will support SL at a time before struggling?, also, and remember that I am quite an ignorant in coding, will it depend of the PC specs or this number will adapt itself independently of the system on which SL will run on?SharpLife supports server-only entities which avoids the whole problem of networking entities to the client and having bandwidth issues. Projectiles don't need to be visible all the time, but networking is also much better so the client can handle more of it on the client, whereas GoldSource just does everything server side and then sends it to the client.
you told me 3d skybox and HD sky is posible.Both are possible.
are bigger maps and bigger textures posible too?
And wad files are pain in the ass too xD could you make it so we dont need wadded textures.Due to how maps reference textures it's not currently possible to ditch wad files since you can only have 15 characters in a texture name, not nearly enough for directory names.
A image file in the mod folder works very well, at least for developing a mod.
One question, what will be the structure of SL?, I mean, will it load a mod directly or it´ll depend of a Half-Life folder with the valve folder and all the rest of junk?, I like the way (don´t flame me please) Xash works. With it you must only create a folder with whatever name you want, you put the Xash exe, three dlls and the very folder of the mod in it and that´s all. Less than 10 Mb in size. And you can launch a full mod as if it was a standalone game (at least if you have all the needed assets in the MOD folder, of course).SharpLife is an all-in-one package, so you'll make a mod that're the game libraries in SharpLife, and deploy the entire engine as a Half-Life mod. This allows each mod to change the engine as needed. Currently the assemblies directory is 11.2 Mb, but that includes debug builds and debug info, so it probably adds up to a similar size when it's all release builds.