Forum posts

Posted 1 day ago2019-03-17 14:35:54 UTC
in Cleansuit scientist won't move Post #342282
They do, they use the follower behavior from that class. That's why i said to use breakpoints in the FollowerUse method, to see what it does.
Posted 1 day ago2019-03-17 10:16:23 UTC
in Model has too many sub files Post #342278
Studiomdl allocates a fixed size buffer 16Mb in size to write each file. It's possible that file write operations can fail if they exceed the total size though.
Posted 2 days ago2019-03-16 21:57:56 UTC
in Cleansuit scientist won't move Post #342268
Breakpoints are not something you add to a function. Read this:
Posted 3 days ago2019-03-15 23:53:27 UTC
in Cleansuit scientist won't move Post #342261
The method is in talkmonster.cpp.
Posted 3 days ago2019-03-15 14:13:31 UTC
in Cleansuit scientist won't move Post #342255
Put breakpoints in the CTalkMonster::FollowerUse method and see what it's doing, if anything.
Posted 5 days ago2019-03-13 10:35:30 UTC
in A Utopia At Stake Post #342250
The engine has a limit to the number of mp3 files it can play. It internally assigns an id to each one and there are a maximum of 200, which includes the files in /media. FMOD doesn't have that limit.
Posted 1 week ago2019-03-09 16:13:13 UTC
in SharpLife - Dot Net Core based modding p Post #342197
I've reworked the command system:
  • Any number of contexts can be shared with any number of other contexts, but circular dependencies are not possible. The internal command context created by the command system is implicitly shared with all contexts (provides the "wait" command), all other contexts must be specified when creating contexts
  • The command system and contexts now implement the Dispose pattern
  • Variable change event handlers can now veto the change
  • Filters are now implemented by aggregating all filters under a change event handler that is always handled first
  • Variables can be made read-only
  • Variables are now strongly typed, and conversion between string and the type is handled by a type proxy object that provides conversion functionality. The command system constructor takes a format provider used to controlling the formatting of numbers (e.g. 123.45 or 123,45 depending on culture settings). Variables can have custom type proxies specified on a per-variable basis, proxy commands can have custom type proxies specified on a per-parameter basis
  • Variables can be virtual (existing version) or proxies to real fields or properties. Fields and properties can be read-only (or have a non-public setter) to implicitly be made read-only)
  • Commands can be proxies to methods that take parameters. Command input will be converted to the target types. Methods can have default values to allow for optional command arguments
  • Added the find command to search for commands using a keyword, potentially containing wildcards
  • Added the help command to display the help info for a named command
Some examples:
//Virtual variable
private readonly IVariable<uint> _fpsMax;

//Creates a modifiable variable, constrained to the range [0, MaximumFPS] (uint does not allow negative values)
_fpsMax = EngineContext.RegisterVariable(
    new VirtualVariableInfo<uint>("fps_max", DefaultFPS)
    .WithHelpInfo("Sets the maximum frames per second")
    .WithChangeHandler((ref VariableChangeEvent<uint> @event) =>
        @event.Value = Math.Min(@event.Value, MaximumFPS);

        var desiredFPS = @event.Value;

        if (desiredFPS == 0)
            desiredFPS = MaximumFPS;

        _desiredFrameLengthSeconds = 1.0 / desiredFPS;

//Proxy variable
public DateTimeOffset BuildDate { get; }

//Creates a read-only proxy variable of type DateTimeOffset
//Type is printed as 03/08/2019 17:21:41 +01:00
EngineContext.RegisterVariable("engine_builddate", () => BuildDate, "The engine's build date");

commandContext.RegisterCommand(new CommandInfo("echo", arguments => logger.Information(arguments.ArgumentsString))
                .WithHelpInfo("Echoes the arguments to the console"));

//Proxy command
private sealed class FindCommands
    private readonly ICommandContext _context;
    private readonly ILogger _logger;

    public FindCommands(ICommandContext context, ILogger logger)
        _context = context ?? throw new ArgumentNullException(nameof(context));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));

    public void Find(string keyword, bool searchInHelpInfo = false, bool searchInValue = false)
        var builder = new StringBuilder();

        builder.AppendLine("Find results:");

        var flags = FindCommandFlag.None;

        if (searchInHelpInfo)
            flags |= FindCommandFlag.SearchInHelpInfo;

        if (searchInValue)
            flags |= FindCommandFlag.SearchInValue;

        foreach (var command in _context.FindCommands(keyword, flags))


commandContext.RegisterCommand(new ProxyCommandInfo<Action<string, bool, bool>>("find", new FindCommands(commandContext, logger).Find)
    .WithHelpInfo("Finds commands and variables"));
The find command is a proxy command with optional arguments, it can be used with just a keyword or with the additional arguments. Finding out which arguments there are is straightforward, using the help command will show you:
help find
find: Proxy command find(String keyword, Boolean searchInHelpInfo = False, Boolean searchInValue = False)
Finds commands and variables
Find works much like help does but can find do partial searches, show multiple commands and perform wildcard searches:
find e*
Command exec
Executes a file containing commands
Command echo
Echoes the arguments to the console
Read Only Proxy Variable DateTimeOffset engine_builddate = 03/09/2019 17:09:58 +01:00
The engine's build date
find * will return all commands.

I'm still reworking the engine so it'll be a while before it gets back to where it was before. I decided to rework the command system now since most of the code that uses it was removed for the redesign.
Posted 2 weeks ago2019-03-03 17:02:40 UTC
in SharpLife - Dot Net Core based modding p Post #342129
I've merged the client and server assemblies into single larger assemblies.

SharpLife.Engine.Client & SharpLife.Engine.Server have been merged into SharpLife.Engine.
SharpLife.Game.Client, SharpLife.Game.Client.Renderer.Shared, SharpLife.Game.Server, SharpLife.Game.Shared have been merged into SharpLife.Game.

I've also updated dependencies to the newest version. Nothing worth mentioning.

I'll probably also merge the model format assemblies into a single assembly.

As far as the rest go, i'm thinking about merging a bunch of assemblies into a SharpLife.Core assembly containing SharpLife.Utility, SharpLife.Engine.API and some parts of SharpLife.Game.

SharpLife.Networking.Shared should be merged in as well, but i'll probably remove all networking code first and add it back later once i've redone the engine and game code structure. Otherwise it'll turn into a mess.
Posted 2 weeks ago2019-03-03 12:12:51 UTC
in TWHL Modded Minecraft Server (Final attempt) Post #342125
I went into your base but i didn't find any skeletons, they've probably despawned on their own.
Posted 2 weeks ago2019-03-03 12:08:10 UTC
in Can't Test Blue Shift Mod Maps Post #342124
You shouldn't copy the content, just add this to liblist.gam:
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.
Posted 1 month ago2019-02-17 14:26:39 UTC
in programmatically changing origin and angles Post #342048
You should always use 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.

Changing pev->angles should work regardless though. Make sure nothing is resetting the angles elsewhere.
Posted 1 month ago2019-02-16 20:24:48 UTC
in TWHL Modded Minecraft Server (Final attempt) Post #342043
Posted 1 month ago2019-02-16 10:07:01 UTC
in programmatically changing origin and angles Post #342036
Show the code you're using.
Posted 1 month ago2019-02-15 12:08:44 UTC
in TWHL Modded Minecraft Server (Final attempt) Post #342028
I've put 3 sets of AE2 presses next to my front door if you need them. I had to clean out 3 meteors to find them all, so the nearby ones won't have any.
Posted 1 month ago2019-02-12 20:20:44 UTC
in TWHL Modded Minecraft Server (Final attempt) Post #342019
I don't think it worked, use the aluminum from this config:

And rename it to aluminum2 or something, because COFH won't regen it otherwise. It won't affect the actual ore, it's just the name used for COFH ore generation.
Posted 1 month ago2019-02-12 18:40:02 UTC
in TWHL Modded Minecraft Server (Final attempt) Post #342018
You also need to make sure that retrogen is enabled in COFH config.
Posted 1 month ago2019-02-12 17:21:17 UTC
in TWHL Modded Minecraft Server (Final attempt) Post #342016
I dug for about 10 minutes and found no aluminum. Which changes did you make and does the log show that it was retrogenerating the ore?
Something like
[12:56:00] [Server thread/DEBUG] [cofhcore/]: RetroGening [-3, 34].
should be showing up.
Posted 1 month ago2019-02-12 11:39:28 UTC
in TWHL Modded Minecraft Server (Final attempt) Post #342014
Thermal Foundation's Aluminium is disabled by default, so making aluminium brass is impossible early game.
It's possible to enable it without having to create a new world by using retrogen:

Just need to add the ore to the oregen file as well:
Posted 1 month ago2019-02-11 14:32:03 UTC
in SharpLife - Dot Net Core based modding p Post #342013
I did some research on how Unity handles commands and remote procedure calls (documentation for those here:

Unity rewrites the code to call a generated method that sends a message to clients (or servers, for Commands) containing the arguments. This makes it incredibly easy to add and use network messages.

Let me give an example by comparing it to GoldSource's approach and the approach i was planning on using with Protobuf.

Here's how you declare a network message and implement it:
//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

//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.

And here's how you use it:
extern int gmsgMyMsg;

	WRITE_STRING( "my message" );
Assuming you're sending it to all clients reliably.

The Protobuf approach would be like this:
Declaring the message:
package SharpLife.Game.Networking.Messages;

message MyMsg
    string text = 1;
Receiving it in code:
public class SomeClass : IMessageReceiveHandler<MyMsg>
   public SomeClass(MessagesReceiveHandler handler)

    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
    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; }.

No registration is needed since that's all automatically generated behind the scenes, there's no need to define separate message types, no manual serialization or sending of messages, and the destination does not need to explicitly register itself since it is identified through its network identity.

This approach is way better and allows for optimizations that are not possible when user code has to manually register things. Since the game codebase is the same assembly for client and server there is no need to send the metadata to validate it either, as long as you've verified that the client is running the same assembly as the server, which is easy to do by comparing the AssemblyIdentity (strong name signing required to prevent spoofing).

It's also more efficient than Protobuf because it doesn't require the creation of objects to serialize.

Also unlike GoldSource and i think Source as well, Unity allows these sort of calls from client to server. In GoldSource the only way to communicate with the server is to send string commands, which is very restrictive. Being able to directly call the server with a specific command on a specific object can make things much easier.

As far as the technical side of things goes, i've found two libraries that could be used to do this: Reflection.Emit (part of .NET) and Mono.Cecil (also works on Core).
Since i've never worked with either i've asked for more information here:

I know that Cecil can do this, but if Reflection.Emit can do the same there is no reason to use a third party library.

As for how this works, it would be a post build step that modifies the assembly. The engine will then load the assembly and use the generated metadata to handle the remote calls.

This article indicates that it should be possible to debug assemblies that have been modified:

So it shouldn't affect that.

This process of modifying assemblies is called weaving, and i've found a framework that does it. However, it's expected that you become a patron of the project if you use it, and that would mean everyone who uses SharpLife would also have to be a patron. Since this is supposed to be completely free i can't use that.

I don't expect that it will be too hard to implement a basic weaving tool by myself since it's largely the same as using Reflection, the only major difference being that i'll have to write IL instructions, which i'd probably have to learn anyway when using Fody:

I think it may also be possible to use the same framework to optimize parts of the component system's internals, like the calls to non-virtual API methods (Update, Activate, etc), so that could prove useful as well.
Posted 1 month ago2019-02-09 14:45:02 UTC
in SharpLife - Dot Net Core based modding p Post #341998
I've done some research on ECS and a regular component system and i've found that using ECS would make it much more difficult to implement Half-Life.
For example things like triggering entities/inputs becomes more difficult because there's no object to trigger.

I think it's also more difficult for the average modder to learn how to use ECS, and if plugins are to be supported then it would be impossible to modify behavior on an object without duplicating the code for it since a component or group of components will be affected by systems that are not under the control of the plugin.

A regular component system like what Unity's had for years doesn't have these problems. While it does have lower performance it can do what's needed while still working like the original. The SDK's code can be converted to a component based design without having to change much, whereas using ECS requires a complete redesign.

I've also done some research to see if the greater overhead of a component system can be reduced, and i've found that it is actually possible:

This article shows that's it's possible to get performance close to direct method calls using Reflection. Using Reflection instead of virtual method calls should make components much cheaper to use. I'll illustrate this with an example.

Here's a naive way to call Update on every component:
foreach (var entity in _entities)

//Entity's Update method
void Update()
    foreach (var component in _components)
Not every component actually overrides Update but the cost of the call still exists.
Here's a way to optimize this using Reflection and delegates:
//Entity's Update method
void Update()
    foreach (var component in _components)
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.

It can be further reduced by moving from a purely object oriented approach to something more effective:
foreach (var component in _activeComponents)
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.

So i think that this approach will work best for this particular project. In the future it may be possible to implement ECS, but that's something to consider after SharpLife V1 is all done.

Also, since this can allow the same code to run on client and server i can probably refactor the existing projects to merge client and server code some more, reducing complexity even more in both engine and game code.

MS will support 7 up to 2023 to patch security issues. By that point you should upgrade to a newer OS so you don't end up with problems.

You can't expect them to support a nearly 2 decade old OS forever. You can't expect application developers to do the same either. With support for XP going away in an upcoming version of Visual Studio we'll have to choose whether we want to continue targeting XP or having access to newer C++ language features.
In C#'s case the newest versions are already unsupported on older systems:

If you honestly think that XP is secure then i hope for your sake that you're right.
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!! XD
Anti 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.
Posted 1 month ago2019-02-04 13:46:09 UTC
in SharpLife - Dot Net Core based modding p Post #341955
The idea behind ECS is that every system executes one at a time so tightly controlling order of execution goes against that.

I'm not sure if there are any practical differences in Half-Life, that's something that can be found by testing it. I can only say that it will be different in terms of when exactly it executes, but it might not be different enough to matter in the end. I'd consider any code and entity setups that are that reliant on this behavior to be bugged, since it's inconsistent.

Building an ECS doesn't seem to be terribly difficult, i've already got a small prototype going to see what it would take. I don't have to consider things like multithreading support so it's simpler than Unity's ECS. In the long run this might actually be simpler than just porting the code since it's so much easier to reuse stuff, and the networking side of things is actually simpler than what i was working on before.

For starters i'll build a non-networked system, but i don't expect there'll be many changes needed to make it networkable. If i apply what i've learned by studying Unity i can eliminate the need for separate client and server versions (much easier since state and behavior are decoupled) which was starting to complicate things a bit.

Save/restore is probably not much different from networking since they both deal with taking variables from components and converting them for something else. I might be able to reuse the code needed for networking to be used for that as well.
Posted 1 month ago2019-02-04 11:17:11 UTC
in SharpLife - Dot Net Core based modding p Post #341952
I've been doing some research on how modern engines handle entities and i've found that there are some options for SharpLife, at a cost.

GoldSource uses the older model of having each entity be a class inheriting from an entity base class. This means that when you create an entity, it will always be the class it is when it's first created. So you can't turn a door into a breakable, for example.

Newer engines allow you to add components to entities to separate out optional parts. Source does this, for example it has a VPhysics component to represents its physics mesh, if it has one.

This still uses the same rigid class based structure as before, but it avoids having variables in the class that aren't always used.

A more advanced version of this uses a sealed base class (can't be inherited from) and adds functionality to entities by adding components. This lets you change entities after they've been created, but adds a lot of overhead to update each component.

The newest kid on the block is called the Entity-Component-System, or ECS for short. You still have a sealed base class and components, but the components contain only state and not behavior. Behavior is provided by systems which can operate on a specific component type, or all entities that have a set of component types.

An ECS is much more efficient than a regular component system because it eliminates the overhead needed to update components. I'll illustrate this with some pseudo code.

A GoldSource style entity system works like this:
for each entity in entity_list do
A component based system works like this:
for each entity in entity_list do
    for each component in entity do
An ECS works like this:
for each system in system_list do
There are far fewer systems than there are entities, and there are far fewer entities than there are components.

This makes an ECS more efficient since it reduces execution overhead. It also allows for more efficient memory usage by adding and removing components as needed.
Networking wise networking individual components is cheaper than networking an entire entity which can save a lot of bandwidth.

Unity for example networks components by networking up to 32 variables per component. By restricting the number of variables they can optimize networking to reduce dynamic memory allocations, something that isn't possible with a traditional hierarchical entity design like GoldSource and Source use.

Now comes the part that's specific to GoldSource: in GoldSource entities think during physics updates like this:
for each entity in entity_list do
    if entity is not world and entity is not player
The world never moves or thinks, and players are handled elsewhere.

The problem with this is that entities will sometimes check other entities near themselves while thinking. For instance teleporters and spawners will check if there are entities at the destination to see if they can move entities or perhaps need to telefrag them.

Because this can happen while other entities haven't moved yet, it's possible for inconsistent behavior to occur. Depending on whether an entity is in the entity list before or after another entity its behavior may change slightly as a result.

When using an ECS the physics update logic necessarily has to be changed to this:
for each entity in entity_list do
    if entity is not world and entity is not player

for each system in system_list do
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.

I'm not aware of any cases where game logic is timed to happen in the correct order in the same frame, but i expect some minor behavioral changes to occur as a result of such a change in design.

So i have a decision to make. Do i go with the older entity design, use a basic component based system (remember, this increases overhead) or switch to an ECS?

For backwards compatibility purposes the original entity based approach will need to be emulated to support the limited entity data format. So a func_breakable would be an entity that has a brush model component and a breakable component, and perhaps an item spawner component that triggers when the breakable component triggers.

Once we can make a new map format it should be possible to use a more powerful entity creation process that would allow you to specify components to add to entities so for example you could make a breakable door relatively easily. This wouldn't happen any time soon though, since that requires a lot of changes.
Posted 1 month ago2019-02-03 11:52:04 UTC
in mod icon Post #341942
Nope, the engine only loads game.tga, and it uses the engine filesystem to load it. So by default it's valve/game.tga, but if your mod has one it'll use that instead.

I'm guessing the tga file is saved in such a way that it appears normal in viewers but gets read upside down by the engine and then flipped.
Posted 1 month ago2019-02-02 23:38:55 UTC
in houndeyes killing each other Post #341935
Then how are you creating the houndeyes? The string passed to Create will be used, but if the string is not allocated or a string literal it'll end up becoming garbage.
You can use 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.
Posted 1 month ago2019-02-02 17:44:47 UTC
in mod icon Post #341927
The engine seems to intentionally flip the image vertically, but i don't know why. I don't know why the original icon works either.

Apparently Github didn't like the previous exe upload, so i reuploaded it.
Posted 1 month ago2019-02-02 11:10:22 UTC
in houndeyes killing each other Post #341921
How are you setting the classname?
No, it's just a program you run locally.
Posted 1 month ago2019-01-28 15:34:20 UTC
in Opposing Force SDK Post #341873
I've put the game installation in its own repository:

The README contains installation instructions. It's still unfinished, i'm currently implementing CTF. Should be done this week if all goes well.
Posted 1 month ago2019-01-27 19:41:54 UTC
in TWHL Modded Minecraft Server Post #341865
I don't think they've created a world yet.
Posted 1 month ago2019-01-26 19:39:27 UTC
in TWHL Modded Minecraft Server Post #341852
Looks like this might be it for you:
See also

RS can store liquids, don't know about gas.
Posted 1 month ago2019-01-26 19:10:37 UTC
in TWHL Modded Minecraft Server Post #341850
AE2 can be configured not to use channels. I personally prefer RS since it's simpler and uses resources that are more easily mass produced (in the old mod pack at least) but with channels disabled they're very similar. AE2's approach to item storage is more expensive than RS so if you just need a mass storage mod then go for RS.

Check these for comparisons:

I'd also suggest some kind of perpetual energy mod like SolarFlux. There may be solar panels in the mods you listed but SF has very powerful ones.

If you're into Chisel & Bits and BiblioCraft i'd suggest taking a look at ArchitectureCraft:
Posted 1 month ago2019-01-25 22:30:11 UTC
in Opposing Force SDK Post #341842
I've implemented everything needed to play the entire singleplayer campaign.

I also went and fixed a bug with the Gene Worm since i encountered it:

Next up is weapon_penguin (CTF only afaik), the unused monster_geneworm (supposed to be able to move, not sure if the code can do it), then both weapons and NPCs are all done.

After that's it's CTF stuff, which also involves client side UI stuff.

Beyond that, i'll need to check existing gamerules for changes and add co-op gamerules, then check if anything else is needed.
Posted 1 month ago2019-01-24 20:07:59 UTC
in Opposing Force SDK Post #341827
The first 9 chapters are fully playable, up to and including Pit Worm's Nest. The next chapter uses a mortar and Black Ops aircraft that need to be implemented.
Once that's done it's just the Gene Worm and the singleplayer will be fully playable.
Posted 1 month ago2019-01-24 13:48:51 UTC
in Can't get func_trackchange to work Post #341823
The track change can only be moved if the train is either on it or far enough away.

Specifically, if the train's current path_track is the path_track that the track change is currently using, or the next or previous path_track connected to that one then you can only move the track change without the train being on it if it's 150 + train length units from the track change's origin, not taking into consideration the Z position of the track change.

So if you want to trigger it, make sure there are path_track entities right at the edges of the track change that the track change path_track entities connect with, that way the track change is only blocked if the train is very close to the track change (if the train is moving to one of the path_track entities at the edge). You'll want to position these so that the train can come to a stop without floating in the air or clipping through the track change when it moves.

If you want to make it possible to trigger the track change as much as possible, place another set of path_track entities right after the edge path_track entities so that the track change's logic doesn't see how close the train is until it's right at the track change. They could be as close as a unit apart, or maybe on top of each-other but that could cause problems with the train's direction.

crisis2 does it this way IIRC.
Posted 1 month ago2019-01-24 11:49:06 UTC
in Can't get func_trackchange to work Post #341819
A Sven Co-op map called crisis2 has a track change that can be moved freely without affecting the train. Maybe see how that's done?
I have some ideas for Half-Life maps that are beyond what the engine can do due to performance issues and limits that boil down to arbitrary numbers in the engine. It shouldn't be this hard to make maps that are larger than the engine supports right now, and performance shouldn't be affected by the technology used to handle graphics.
Yeah i think they want us to reverse engineer the older games as well, since the amount of information found in the libraries is way too much to account for just debugging purposes.
Posted 2 months ago2019-01-18 16:31:42 UTC
in Opposing Force SDK Post #341712
Does anyone have an up-to-date fgd for Opposing Force? I think i have this one:

It's missing some stuff, so if i could get a newer one i can add anything that's still missing.

Edit: found it, thanks Shepard:
Posted 2 months ago2019-01-16 19:25:01 UTC
in Opposing Force SDK Post #341703
I've documented how the relationship table can be extracted from the game:

Requires a Linux VM or OS.
Posted 2 months ago2019-01-16 17:18:32 UTC
in SharpLife - Dot Net Core based modding p Post #341701
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 wasnt
Half-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:
Posted 2 months ago2019-01-16 17:14:23 UTC
in Opposing Force SDK Post #341700
I'm currently working to implement Opposing Force in the Half-Life updated SDK:

I decided to do this now because i know that it will be a while before i can get to this if i make it part of SharpLife, and since i have to reconstruct the original C++ code anyway before i can convert it i figured i'd get it done now, so people can use it and find any mistakes/bugs before it gets converted.

So far i've implemented CTF gamerules, which is about 2000 lines of code. Other gamerules need to be updated, and the co-op gamerules need to be implemented as well.

I'm going to start with the NPCs now, since that's the interesting part and because that's what the largest part is.

Implementation is based on what's needed to make single maps work, starting with the training maps, then the campaign, then multiplayer. This way it can be tested more easily.

The ultimate goal is to make an SDK that completely implements Opposing Force. You won't be able to copy paste it into your own mod unfortunately since it changes existing SDK code (some network messages are different, gamerules are different too). When the time comes i'll port it to SharpLife, integrating all of the features so that you can play Opposing Force as well as Half-Life using the same base game, and use any features present in either in your maps.

I'm not doing a 1:1 reconstruction, there are places where i'm making use of newer language features and simpler code to make things easier. For example, iterating over players is done like this:
int 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.

Iterating over entities is similar:
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)

I've also added helpers to make it easier to do type conversions:
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.
Posted 2 months ago2019-01-16 16:48:17 UTC
in SharpLife - Dot Net Core based modding p Post #341698
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. :glad: :walter:
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.

If C++ is chinese then C# is dutch. It's way easier to learn and use. C++ has a lot of complexity and gotcha's that don't exist in C# and IntelliSense and the compiler will tell you how to fix most problems in C#. I'm using extensions that find code that can be improved which also helps out a lot.
btw can we make another thread for SL v2 for not to forget cool ideas. and not to flood this thread with weird ideas. :D
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. :D
I was already going to implement co-op (Opposing Force has a co-op gamemode in it), what do you mean by unbroken?

Seamless level transitions basically revolve around 2 things: not showing the changelevel dialog and transitioning entities, which singleplayer code already does. For multiplayer all that's needed is to track which player is which since they don't remain connected during transitions. That's not very hard to do.
Posted 2 months ago2019-01-16 13:24:48 UTC
in SharpLife - Dot Net Core based modding p Post #341693
You're getting way ahead of yourself here. SharpLife doesn't even support all of the original engine's features yet, talking about adding a bunch of new stuff now is far too soon. At this rate it'll end up being some mythical super engine that can do anything but doesn't actually work yet.

We can talk about this stuff later on, when the initial version is finished. For now i'd like to focus on getting it all to work as it should.
Posted 2 months ago2019-01-16 10:01:38 UTC
in SharpLife - Dot Net Core based modding p Post #341690
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. :crowbar: :D
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.
Background maps will be a thing for later, when the engine is stable.
Posted 2 months ago2019-01-15 20:36:26 UTC
in SharpLife - Dot Net Core based modding p Post #341682
I'm not translating it, i'm making a new engine that's also a mod that lets you make Half-Life mods and load original content.

If you want a better engine other than Xash then you'll have to wait.
Posted 2 months ago2019-01-15 20:19:19 UTC
in SharpLife - Dot Net Core based modding p Post #341680
Yeah your example is pretty much how save/restore should work.

C# is much easier to use than C++. I'll show a couple SDK examples to show this.

This is some code that shows up a lot in gamerules classes:
	"\"%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.

This is for logging, for normal string formatting you can just use string interpolation:
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.

EHandles can also be made safer:
CTFGoalFlag pFlag = ( CTFGoalFlag* ) ( CBaseEntity* ) pPlayer->m_pFlag;

if( pFlag )
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.

I've also had to write this code recently:
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.

This is all pretty basic stuff, it gets easier once you deal with entities more:
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_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.

Network messages will also be easier to use, right now they're just Protobuf messages so you can easily create and send them without having to worry about getting it wrong.

Debugging is also much easier since it'll tell you where a problem occurred, for example here's the log entry for a fatal error where it failed to load a sprite:
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.

Compare this with GoldSource or even just C++ debugging where something like this is little more than a message box telling you there was a fatal error, without actually pointing you at the code that triggered it.

Once you get used to the language you'll find it's much easier, you won't want to go back to C++ after this.
Posted 2 months ago2019-01-15 16:53:22 UTC
in SharpLife - Dot Net Core based modding p Post #341673
Also it's written in a different language and has a different API so existing mods can't run under it anyway.