Forum posts

Posted 6 years ago2018-09-11 15:32:51 UTC
in SharpLife - Dot Net Core based modding p Post #340851
It is doing backface culling, no visleaf checking yet. We talked about maybe not using visleaves because it might actually lower performance. I'll have to try it out and see what the results are.
Posted 6 years ago2018-09-10 19:36:34 UTC
in SharpLife - Dot Net Core based modding p Post #340842
I've optimized BSP rendering as much as i can for the time being. Bounce is hitting close to 1300 FPS now, singleplayer maps like c1a0c (Unforeseen Consequences), c2a5 (Hydroelectric Dam), c3a2c (Lambda Core portal jumping puzzle) run at around 600 FPS without any visibility testing.

I also tried this map: https://twhl.info/vault/view/6174
It runs at about 250 FPS.

I did this by reworking a couple things:
  • Shared BSP resources are allocated once, reducing the number of state changes
  • The light styles are passed as a single uniform buffer (only 64 actual values are needed, reducing memory requirements). Each vertex also stores the styles used for it, eliminating the need to group surfaces by which styles they use
  • A single vertex & index buffer is used for an entire model
  • Lightmaps are pooled together in larger images like vanilla GoldSource does. These pools are larger than vanilla to reduce the number of state changes required to switch lightmaps. Unlike vanilla, there is no limit applied to how many pooled lightmaps there are, and the pools are not shared between models. I can change this to reduce GPU memory requirements, but it shouldn't affect performance unless a lot of nearly full pools are reused, which would cause a lot of state changes to happen when rendering BSP submodels (brush entities)
  • All of the surfaces that use a texture are grouped together, ordered by number of surfaces descending and then added in sequence, allowing surfaces with the same texture to have their lightmaps in the same texture to reduce state changes. Ordering by number of surfaces ensures that maximum efficiency is attained in grouping lightmaps together, reducing the number of state changes required a little more
Light style changes barely affect performance now, i applied random modulation as a test and the FPS drop is manageable. Bounce suffers a drop of around 100 FPS, but c3a2c only drops by about 60 FPS. Considering every single light style (64 styles) is changing at once every frame, that's pretty good. Most of the time only one or two change, and they usually don't change as frequently as this. In practical situations it shouldn't affect FPS that much, certainly not as much as people get with the vanilla engine.

Dynamic lighting will probably lower things a bit, but those are usually temporary effects so the FPS cost shouldn't be that bad.

EDIT: I implemented support for Vulkan, here are the results:
  • Bounce: 1950 FPS
  • c2a5: 1000 FPS
  • c3a2c: 900 FPS
  • dm_crossedwire: 360 FPS
Pretty good, i don't think there'll be any performance issues.
If you can modify the code you can change it here: https://github.com/ValveSoftware/halflife/blob/5d761709a31ce1e71488f2668321de05f791b405/dlls/hgrunt.cpp#L1204

Change the EMIT_SOUND to EMIT_SOUND_DYN and pass in a different pitch to it. You can see how to use EMIT_SOUND_DYN in EMIT_SOUND.
Posted 6 years ago2018-09-09 17:57:19 UTC
in Wtf bug in game Post #340837
The only thing i can think of is that the name was too long. 15 bytes is the maximum, and the game only considers the first 12 when doing material lookup. Could be the name happened to trigger a bug in that code.
Posted 6 years ago2018-09-09 13:25:20 UTC
in SharpLife - Dot Net Core based modding p Post #340831
User posted image
Lightmaps are working, including styles. It's not terribly efficient yet, but i'm working to make it better.

I'm going to implement render modes as well to make sure BSP rendering is mostly done.

After that i'm going to take a look at figuring out what could be causing memory leaks, since the game is crashing after a few maps with a lot of memory usage. Since it's not a C# exception it must be native memory somewhere.

EDIT: looks like it is a C# exception, so something is using up memory somewhere.

EDIT2: found the cause: https://github.com/mellinoe/veldrid/issues/118

A memory leak in Veldrid's OpenGL backend causes the problem.

EDIT3: the leak has been fixed. I've upgraded to the latest Veldrid build and i've also upgraded to the latest ImageSharp beta (since Veldrid needs it). ImageSharp is now pulled from NuGet, Veldrid is still a custom build since there is no full release containing the needed fixes.
Posted 6 years ago2018-09-07 16:35:01 UTC
in TWHL4 Discussion / Bug Reports Post #340813
There's a link "Formatting help" above the text area that links to a page that shows what kind of formatting you can use. That includes code blocks.
Posted 6 years ago2018-09-07 12:11:49 UTC
in skill data issue Post #340809
Posted 6 years ago2018-09-07 07:25:42 UTC
in SharpLife - Dot Net Core based modding p Post #340807
I can't legally use Quake code in any way, shape or form. We went over this a while back in this very thread.
Posted 6 years ago2018-09-07 07:24:25 UTC
in skill data issue Post #340806
You also need to add new variables to the skilldata_t data structure. Gamerules will copy the values from cvars into this structure, which game code will then use.
Posted 6 years ago2018-09-06 17:08:37 UTC
in SharpLife - Dot Net Core based modding p Post #340802
The vanilla engine doesn't handle frame groups (a frame that contains a variable number of actual frames), it just complains about missing frames ("R_DrawSpriteModel: couldn't get sprite frame for <model name>"). I haven't implemented it either since there is little point in adding that kind of overhead, and no existing sprites would have it anyway. Given that Quake 2 does away with it, it likely never saw widespread use in Quake either.
Posted 6 years ago2018-09-06 14:10:38 UTC
in SharpLife - Dot Net Core based modding p Post #340799
I've mostly implemented sprite rendering:
User posted image
I've implemented sprite loading, image conversion to RGBA32 using the alpha channel to store transparency without modifying the original color data, rendering sprites under all render modes, including a bug that makes Color not apply a color, and apply the right angles based on sprite type.

I reported this bug: https://github.com/ValveSoftware/halflife/issues/1903

I fixed a bug with the "facing upright" sprite type: in GoldSource this uses the model origin from another entity so it will snap around depending on which entity last set it before the sprite is rendered. I could reproduce the original behavior, but since it depends on render order it would never really be the same.
Given how rarely this type is used, and the fact that the bug was fixed in Source, i figured it wasn't worth replicating the original behavior.

I reported this bug as well: https://github.com/ValveSoftware/halflife/issues/1904

Neither of these bugs will ever be fixed in vanilla because some maps may rely on it, i reported them so people can find them more easily.

All that's left as far as sprites are concerned is depth sorting to make sure transparent sections don't block other transparent sprites from rendering.
You can see this problem in the image: the green lambda icon on the right is blocked by the stop sign sprite.
Depth sorting is also required for brush and studio models that have transparent parts.

Once this is done i'll implement render modes for brushes, fix skybox rendering to make sure transparent objects don't cut holes in it and to make sure sprites always render on top of it, take a shot at lightmaps and then finally handle studio models.

Once that's done i can implement render FX, which should wrap up all things model rendering related.

I also had to implement some entity keyvalues to make this all work enough to test things out, and i found a bug in the networking system's converter for vector types where it didn't decode them correctly.

Hopefully this can be wrapped up soon so i can start implementing physics, that's needed to make things like glow sprites work (it tests if a sprite is blocked by something else).

Thanks to The303 for making tutorials and test maps to display the various sprite types and render modes.
Posted 6 years ago2018-09-03 13:08:28 UTC
in Half-Life SDK updated for use with VS2017 Post #340784
There is no #include <math> in this project. Where are you seeing that?
Posted 6 years ago2018-09-03 12:44:59 UTC
in Half-Life SDK updated for use with VS2017 Post #340782
I've fixed a couple other functions, it should be good now.

Normally i'd clean this all up by moving all of the function declarations to mathlib.h, rename pm_math.cpp to mathlib.cpp, use the same file for all games (there are 3 copies of pm_math.cpp, one for each game in the SDK), and use the Vector class everywhere. Unfortunately that would take a fair bit of time to clean up, and this was supposed to be a quick fix for people trying to make mods with VS2017. The fix i've done here is pretty ugly (multiple forward declarations of math functions to avoid conflicts between the old C and C++ code), so if you want something clean you'll have to deal with this.

Math.h isn't related to this by the way.
Posted 6 years ago2018-09-03 12:17:17 UTC
in Half-Life SDK updated for use with VS2017 Post #340780
It has nothing to do with const. The problem here is that there are overloads of functions that use types that are actually the same.
Some compilers consider typedefs to create distinct types, others just use the underlying type.
A function taking a vec3_t is identical to a function taking a float[3], which is identical to float*.

I've correct a couple of them to make things work, try it out and see if there are any more.
Posted 6 years ago2018-09-03 11:07:40 UTC
in Half-Life SDK updated for use with VS2017 Post #340778
I've updated references to min & max to use V_min & V_max. Your problem should be solved now.
Posted 6 years ago2018-09-03 10:52:37 UTC
in Half-Life SDK updated for use with VS2017 Post #340776
We're not rolling back because unrelated programs don't work on 18.04.

You're having issues compiling because you're on a 64 bit system trying to compile a 32 bit, but the error that's stopping compilation is that it can't find pm_shared files. I converted those to C++ after Shepard's pull request, so he didn't see it. I've pushed changes to the makefiles to make it find the correct files, pull it and try again.

You'll probably have issues linking due to cross-compiling issues, i suggest you look at tutorials for setting that up properly before trying to compile this.
Posted 6 years ago2018-09-03 08:59:06 UTC
in Half-Life SDK updated for use with VS2017 Post #340772
By request i've updated the Half-Life SDK to work out of the box with VS2017. The projects have been converted to use the v141_xp toolset, all warnings and errors have been fixed.

You can get it here: https://github.com/SamVanheer/halflife-updated

Changelist:
  • Converted project files to VS2017, toolset changed to v141_xp (utils may not compile due to missing third party dependencies such as 3DS Max headers, GLAux library headers)
  • Removed VS2010 projects
  • Removed fabs macro definition, updated ambiguous uses of abs to use fabs function
  • Removed old dll copy build step (depends on relative location to game install, would cause errors)
  • Disabled CRT secure warnings (codebase is full of unsafe function uses)
  • Refactored platform specific code handling (Platform.h handles abstractions now)
  • Corrected invalid fprintf variadic arguments in nodes.cpp
  • Removed unused typedef specifier that caused copious amounts of warnings
  • Converted player movement code to C++
  • Fixed some incorrect math function declarations & definitions (declaration used vec3_t or float*, definition was other way around)
  • Updated Makefiles and gendbg.sh
  • Added fixes for Linux (GCC 8)
  • Fixed signed/unsigned comparison warning
  • Refactored dllexport macro definitions (defined in Platform.h now)
  • Removed invalid preprocessor command start token (#)
  • Use Platform.h instead of Windows.h where winsani is required (workaround for sprite handle type conflicting with Windows handle type)
  • Commented out EIFACE_H following #endif (can cause compiler warnings/errors)
  • Set /Zc:threadSafeInit- to ensure mods work properly on XP
Thanks to Shepard for providing the fixes for Linux.
Unfortunately there is no way to directly access the engine functions for getting surfaces from positions in the world, so you'll have to fake it by creating a trace that uses the original start and end positions. Since pmtrace_t doesn't have that, you'll have to pass it into the function yourself.

EV_HLDM_GunshotDecalTrace gets called by EV_HLDM_DecalGunshot, which is called by the code that performs the trace. Modify both to take the start position as a parameter, and pass it in.
Use gEngfuncs.pEventAPI->EV_TraceTexture to get the name. This function will do a trace and returns the name of the first brush texture it hits, or null if it didn't hit anything or if it hit something other than a brush.
Posted 6 years ago2018-08-29 13:32:56 UTC
in SharpLife - Dot Net Core based modding p Post #340733
I've been reworking the renderer and model loader to prepare for the other formats. I've merged the server and client interfaces for models and it handles path separator characters properly so for example maps/bounce.bsp and maps\bounce.bsp are considered the same.

Graphics resources are managed separately from rendering state and rendering is now handled by the game, which means when the renderer wants to render models the game can handle the entire thing.

In addition entities can now set their model, which is networked to clients. The model is set as an IModel, rather than an index. This means you can just use the model object, and the networking system will handle conversion to and from the index for networking purposes. This simplifies things and eliminates the need to look up the model whenever it's needed.

I've removed the temporary code to render all BSP models as this is now handled by the game, rendering the world and a basic version of func_wall:
User posted image
The grates and the doors are func_wall.

No render modes yet, but it's easy to add. Due to how it's implemented it's possible to let the game issue render calls and then handle it on another thread if needed since all relevant data is passed into the renderer by the game. This should allow the renderer to run on its own thread without needing to lock for access to the game; the game can collect its render calls and then pass that along, minimizing thread sync time to a single operation. That's going to have to wait for later on though.

I fixed a bug in the BSP loader where submodels were off by one due to a misunderstanding in how the engine loads them. Even the Quake codebase says it's confusing, so it really was confusing. It's all good now though.

Pretty much everything's in place to add sprites and studio models into the mix now.
Posted 6 years ago2018-08-26 14:08:46 UTC
in SharpLife - Dot Net Core based modding p Post #340682
That has nothing to do with this project.
Posted 6 years ago2018-08-26 13:05:10 UTC
in SharpLife - Dot Net Core based modding p Post #340680
I'll probably use Core 3.0's UI support or Avalonia, not GTK.

[TC]Čiαиєz asked if the HUD can be scaled. This is possible in vanilla GoldSource if you modify the HUD code, and i'll keep it in mind when designing the HUD code for SharpLife.

https://github.com/MiYanni/xBRZ.NET may be a good library to use for scaling the images while retaining a sharp appearance.
It's difficult to convert for most people because they don't know how to do it. If you do know then you'll want to convert them.
The SDK on Github doesn't use CMake.
Posted 6 years ago2018-08-23 20:07:05 UTC
in SharpLife - Dot Net Core based modding p Post #340647
The plan is to have plugin support, that will allow you to have entities added without having to modify the mod itself.
That also includes weapons, but i'm not sure how safe it would be to allow those to be client predicted since that would require downloading the code to the client.

It should be perfectly possible to have plugins that can both replace and add entities, same with map specific scripts. I don't think we should go overboard with that though, otherwise people will spend more time downloading various scripts than actually playing.

Those entities can use the config feature i talked about before.
EDIT: i've completed the essentials to load models, the map is now loaded using a model manager. The old map manager has been removed and its features merged into the model manager, or moved elsewhere.

Right now the following features are available:
  • Models can be loaded at any time by calling IServerModels.LoadModel or IClientModels.LoadModel (these interfaces may be merged since they're currently identical)
  • There is no limit to the number of models you can load, aside from hard memory limits (RAM and GPU)
  • Model data is shared between client and server, so listen servers are guaranteed to use the same data, though graphics data is stored separately
  • If a model fails to load, the fallback model "error.mdl" (renamed can.mdl from Half-Life for now) is loaded. If the fallback fails to load the game will exit with an error, but i may change it to instead create an empty model. That will have to wait until studio model loading is complete. I'd prefer to avoid having hard exits if at all possible, so this would be nice to have
  • The client can load models without having them loaded on the server. Vanilla GoldSource will silently fail to do anything when calling gEngfuncs.CL_LoadModel and returns null in this case. If the server loads the model later on, it will simply have both a positive index (networked) and a negative index (client specific). There is almost no overhead involved with this, it's just an additional entry in a dictionary
  • The map is now loaded into graphics memory after all resources have been received, matching the original engine's behavior
  • Map information can be retrieved from the engine using IServerEngine.MapInfo or IClientEngine.MapInfo. This provides a read-only object containing the name of the current map, the name of the previous map and the map's world model
  • Game code can directly access the model data by calling IServerModels.GetModel or IClientModels.GetModel. This returns an IModel, which can be cast to the specific model type that contains model data. Type identification replaces vanilla GoldSource's modtype_t here
C#'s pattern matching makes dealing with different types of models a bit easier:
switch (model)
{
    case BSPModel bspModel:
        {
            break;
        }

    case StudioModel studioModel:
        {
            break;
        }
}
It's easy to handle specific types of models this way.

This will need to be stress tested to make sure it's all working properly, but that'll have to wait until studio & sprite loading is done. I'm going to start with sprites since those are the easiest to work with.

Once that's done i'll have to implement the uploading of late precached models to the GPU, since the current design is optimized for loading everything in one go after resources are received.
Posted 6 years ago2018-08-23 12:39:21 UTC
in SharpLife - Dot Net Core based modding p Post #340642
Yeah it is quite a bit of work, but it's way easier to do this in C# than it would have been in C++. IMO C# has a more complete standard library and open source community than C++, so it's easier to get things done without having to reinvent the wheel (just take a look at how Unicode and internationalization is handled in C/C++).

I've fixed the issue i was talking about, i've also refactored the networking code to move most of it to NetworkServer and NetworkClient. I've also reworked the server's setup code for clients to centralize the logic for each stage, but i might rework that later on to use objects that can handle each stage, that's more robust and reduces the amount of variables that are only used during setup.

I've reworked networking objects to use the builder pattern to ensure that all networking data structures are immutable after they've been initialized. This should help prevent accidents that could cause unexpected errors.

Now i can implement model precaching, and model loading after that.
Posted 6 years ago2018-08-22 12:48:09 UTC
in SharpLife - Dot Net Core based modding p Post #340630
Right now the new limits can be used with existing tools, but there are hard-coded limits in the tools that came with the SDK. For instance, QLumpy sets the maximum lump size to 327680 bytes, or about 327 KB. Each textures is stored in a lump, so that's a limitation. Removing the limit is pretty straightforward, just replace the tool with another that can store any size texture.

The compile tools and BSP format impose limits, some of which can be raised or removed by modifying the tools, but the BSP format itself presents a hard limit on its own. A new BSP format is needed to deal with that, which also means new compile tools that can produce those BSPs, and a new .map format to handle any changes in how data is passed from the editor to compile tools.

For now the plan is just to let you use existing maps in SharpLife, and where possible the limits are removed or raised.
The maximum number of entities as well as the maximum size in bytes of the data is imposed by the compile tools as well. VHLT34 supports up to 16384 entities, and a maximum data size of 2097152 bytes, or about 2.1 MB.
This limit can be entirely removed by using dynamic allocation and not imposing any maximum limitation, since the hard limit is defined by engine devs (65534 for now), and is solely a networking and memory usage limitation.

I doubt anyone will hit the compiler limits any time soon, so you can make more entities if you want. Textures can be larger than before without hitting lump size limits, but eventually you'll get there. A way to reduce that chance is to not store mipmaps, since the engine can regenerate those, but that requires modifying the wad creation tool of your choice. I don't know if Wally has any limitations so i can't say anything about that, but i can reverse engineer it and take a look if you want to know.

When it comes to upgrading or replacing tools i'd wait until SharpLife is capable of doing everything the current engine can do before looking too much into it. It may be easier to deprecate wad files entirely rather than try to remove its limits, same for other file formats.

I think the biggest limit is going to end up being the fact that SharpLife is 32 bit, required because it's hosted by a 32 bit process. I can't get around that unless Valve helps us out here. Fortunately that doesn't apply to tools, so compile tools can be 64 bit if needed.

Does that answer your question, or did you need to know more?

EDIT: i've committed the entity list code, the world is now instantiated from the map's entity data. Other entities will be instantiated once they've been ported over.
The world is networked to clients, so they'll be able to get any networked members that it has (currently origin, angles, flags).

Entities can be networked as a base type when there is no need for a specific type (e.g. NPCs can probably use a common base type), allowing them to be networked without requiring you to create client versions for every single one.

Now i can implement model precaching and start working to implement model loading and rendering.

There is currently an issue where starting another map after one has been started will cause an exception due to duplicate network string lists, i'll fix that shortly.
Posted 6 years ago2018-08-17 20:35:40 UTC
in (Release) Half-Life: Echoes Post #340586
Mr Gnang, i'm going to do this here since i've probably filled up the Facepunch thread enough. I ripented echoes12 to see if there are any entity setups that could be causing problems. I found a couple multi_managers that could be creating excessive amounts of copies due to unnecessary keyvalues.

Multi managers blue1_repeatmm and blue1_mm call each-other almost immediately, and both have a keyvalue "m_flRadius" with a delay of 512. I'm seeing the exact same keyvalue and value in a lot of entities, mostly scripted sequences.
There is no entity by that name, but there are keyvalues by that name for entities scripted_sequence, scripted_sentence and env_sound.

I suggest removing these keys. It'll allow the multi_manager clones to be removed much sooner (about 511 seconds sooner), drastically reducing the number of entities and the amount of save game space required. It may also eliminate the need to use num_edicts, but you'll have to test that.

I would also suggest checking all other multi_managers for similar keyvalues, as well as any other entities that don't use such a keyvalue (ammo_buckshot for instance).

If you did not add these keyvalues, whether directly or by copying and modifying other entities, double check your fgd file for incorrect keyvalues and/or baseclasses.
Posted 6 years ago2018-08-17 14:15:57 UTC
in Competition 35: Vanilla Half-Life Post #340579
They're just joking SSB.
Posted 6 years ago2018-08-16 07:32:43 UTC
in why are you mapping/modding Post #340561
I got interested in modding because i like to create environments. I used to play with Lego when i was a kid, so this allowed me to do much more.

I'm making a mod now because i wanted to do something nice for everybody since Half-Life and Sven Co-op got me some fun times as a teenager. Once i'm done with making it i can make the maps i've always wanted to make, with no limits and every entity i'll ever need.
Posted 6 years ago2018-08-16 07:30:30 UTC
in Competition 35: Vanilla Half-Life Post #340560
I might rework an old map for this, if i have time.
Posted 6 years ago2018-08-13 18:29:11 UTC
in Competition 35: Vanilla Half-Life Post #340531
I don't think there's a limit to entity names, the save/restore code can handle any length but there may be other places where there's a limit.
Posted 6 years ago2018-08-13 14:54:46 UTC
in Competition 35: Vanilla Half-Life Post #340524
The limit for map names is 31 characters. Various parts of the engine and the game use different limits, but that's the lowest limit i know of.
Posted 6 years ago2018-08-13 14:09:29 UTC
in SharpLife - Dot Net Core based modding p Post #340518
That should be possible using CSharpScript: https://github.com/dotnet/roslyn/wiki/Scripting-API-Samples

Those examples are pretty basic, but it should be possible to build a scripting API that enables you to create your own entities and access other entities as needed.
Custom monsters should work fine, but networking custom data may not be as flexible as it would be if written in C#.

For plugins, custom assemblies can be used instead. You write C# code and tell the game to load it as a plugin, you can then provide entities, hook into other objects and do what you want to do.

Custom monsters largely need support for schedules. I'm going to use a new design for that instead of using Half-Life's approach, it should be more modular so you could do something like this:
public Barney()
{
   this.AddSchedule(new Follow());
}
Follow would be a class that implements an ISchedule interface, providing a list of tasks to complete in that schedule, as in Half-Life. The big difference is that the schedule and task code would reside in the schedule object, and be flexible enough to avoid knowing the actual NPC type most of the time.

A schedule that has an NPC attack something would instruct the NPC to attack using the preferred weapon for a range (close range: don't use weapons that deal splash damage, long range: use accurate weapons). Barney would always use his pistol, so it would look something like this:
public virtual void AttackTarget(BaseEntity entity, float range)
{
    //DefaultWeapon is a property that returns the default weapon for an NPC. NPCs can override it to provide logic to decide what the default weapon is at a given time, but complex logic belongs in this method
   var weapon = DefaultWeapon;
    //NPCs that don't have weapons don't attack
    //They shouldn't have schedules that would instruct them to attack, but if they do, it can be handled here
   if (weapon != null)
   {
      AttackTarget(entity, weapon);
   }
}

public virtual void AttackTarget(BaseEntity entity, BaseWeapon weapon)
{
    //Figure out where to aim, tell the weapon to fire, etc
}
Implemented in the base NPC class so any NPC will try to attack if they have a weapon.

Most of the hard logic would be handled by base classes, weapon classes will take care of actually firing the weapon (weapon_9mmhandgun fires a 9mm bullet fired by Barney) and handling magazine size and reloading. Other weapons, like the Alien Slave electrical attack would also be a weapon for consistency, meaning it's possible to turn it into a player usable weapon (a la Decay).

Making a basic NPC like Barney would mostly be combining existing schedules shared between NPCs, setting the correct ally settings ("i am Black Mesa personnel") and the weapons the NPC can use. This could be turned into a configuration based setup, so an NPC would be defined by loading a config containing the settings. You'd then override the config by inheriting from that and setting values:
<!-- The Base attribute tells the loader to first load the given config file, then merge the values with values loaded from this config -->
<EntityConfiguration Base="NPCs/barney">
    <!-- ConfigAction instructs the loader how to handle merging, in this case clearing and overwriting the old values. Default is merge, overwriting duplicates -->
    <Weapons ConfigAction="ClearAndOverwrite">
        <!-- This Barney uses a shotgun and it's his default weapon. Note that this requires Barney to have animations to fire shotguns and provide attachment points to put the model onto -->
        <Weapon ClassName="weapon_shotgun" IsDefault="true"/>
    </Weapons>
</EntityConfiguration>
It's called EntityConfiguration because it could be used for entity configurations in general.

I'd like to point out that Half-Life only supports up to 4 attachments. This is a limitation in the client, mostly the renderer, and there is no need to impose that limit here. The studiomdl format can store up to 512 attachments if using the default compiler, custom compilers can extend that limit to theoretically unlimited.

That makes adding attachments for weapons pretty simple, the only issue is that while attachments do have names, the default compiler doesn't let you specify the name. I'll have to modify it allow for that, otherwise attachments will need to use their index to identify them.

Unfortunately there is a backwards compatibility check in the studiomdl compiler that makes adding the name a bit complicated. I could make a separate program that sanitizes existing QC files to remove the obsolete tokens, then i can add the name as an optional last argument for $attachment. I'll have to look into that at some point in the future.

For anyone interested, the backwards compatibility check is to parse and ignore the tokens "X" and "1" or "-1". The Half-Life SDK on Steam has model sources containing these, i don't know what they were for but if i had to guess it was some kind of axis specific scale or something.

Getting back to the config files: at this point it's just an idea, until we get to the point where entities can be fully implemented this is just a dream. But if we get there, i'll definitely make it as easy and powerful as possible. I want you to be able to take SharpLife and modify only config files to produce a different looking mod, so no programming experience should be required.

For mappers, you'd just set the entity config filename to something like "maps/my_map_name/NPCs/MyBarney" to use the script for a specific Barney, it would also be possible to specify a per-entity class default using a config file for maps:
<MapConfiguration Base="maps/DefaultMapConfig">
    <DefaultEntityConfigurations ConfigAction="MergeAndOverwrite">
        <DefaultEntityConfiguration ClassName="monster_barney" ConfigFileName="maps/my_map_name/NPCs/MyBarney"/>
    </DefaultEntityConfigurations>
</MapConfiguration>
It's ambitious, but unlike the HLE version i had planned, this one doesn't require a complicated third party dependency setup, and it's much easier to load XML files due to being able to map them onto C# data structures. Text encoding is handled by C# so it's a lot simpler to work with than Xerces was.

Right now the focus is on the engine. I'm finishing up the networking code now, once i'm sure it's working properly i'll integrate it into SharpLife and see if it works well in the existing networking system (i haven't tested it with actual network packets). Then i can integrate my entity list prototype and see if a basic entity can be networked over. Then i'll make a worldspawn entity along with the logic to parse out entities easily.

Once i'm sure that's all working, i can focus on model loading. I've already got a partial prototype for studiomdl loading so it's making progress. I'll need to load the BSP file (already done), studio models and sprites. The server has to do 2 things: add the filenames to the precache list (easy) and load the models (hard). BSP loading is done and most of the rendering code is there. Sprite loading is pretty straightforward to do, but studiomdl is complicated because the format has unused features.

I need to make sure everything that's needed is loaded and converted properly to make it efficient enough, and avoid loading data that isn't needed. Texture data isn't needed on the server side, but the server and client can share data so making sure it loads correctly is important.

Once model loading is done, and the interface to get models for entities is there, it should be possible to render an entire map, including brush and point entities. Models will be precached by the client and rendering settings will be networked so clients can correctly do things like render { textures or sprites with transparent parts.

Getting studio models to render will be the hardest part, since i don't yet know how to handle the uploading of the vertex positions. I don't think re-uploading them every frame is good, so a way to do the vertex position calculations in a shader would solve that problem. I'd probably have to pass the bone positions as a uniform for that, but i don't know if that's a good way to do it. If anybody has experience doing that, i'd love to hear about how you did it.

I've covered a lot now, so i'll focus on getting this all done rather than talking about it more. Hopefully i can show this all off by the end of the month, but that depends on how much work i've got for college.
Posted 6 years ago2018-08-12 21:26:01 UTC
in SharpLife - Dot Net Core based modding p Post #340506
The idea behind the project is the same, it's a different approach though.

C# is a much easier language to work in, i don't have to worry about some issues that make API design hard in C++. I've made much more progress working on this than i did working on HLE, and that has to do with there being much better third party libraries to provide functionality. The .NET framework itself also covers a lot of features that are missing in the C and C++ standard libraries, which eliminates the need to provide those myself.

The language also provides much better debugging features, if you crash you'll be able to see what happened in the log, unless the crash was so serious it never makes it to logging the error.

At the rate i'm progressing i should have the essentials for entities up and running in a few weeks, which means i'll have model loading done which should let me add the minimum required entities to make a map.

I'm not limiting myself to MP features, these things are necessary even in SP because that's how the engine works. Using the same way to send data to the client makes things a lot simpler.

Sven Co-op has nothing to do with this project. It's just another mod that lets people do stuff, i'm working on this for the same reason that i joined that team in the past, which is to make something nice for people to play around with.

Getting a working build is not just a matter of implementing the minimum required engine features, without the entities it's not going to let you do much.
Once i've got the object networking code done the networking part of things is largely finished. It will require fine-tuning and optimization, but if it works it's enough to start building on top of it.

I've actually covered a large part of the engine already, the biggest missing feature is a proper GUI, which is a fairly low priority since the console provides enough control to get things done for now.

Feature wise this engine eliminates most of the engine limits. The design i've got planned for networking allows for up to 65535 entities to exist at any one time. This limit is dictated by the size of the data type used to store entity indices, and is easy to change. The rest of the codebase should adapt automatically to increasing numbers of entities. I can probably do the same for map sizes, where i can change the networking configuration for coordinates based on the size of the map to optimize bandwidth usage.

The limits you know about the original engine are things like texture size, map size, entity count, player count, etc. All of those are either gone or configurable so it's not really a limitation anymore.

Because this engine uses shaders graphics performance is much better. That means r_speeds is no longer something to keep in mind, so you can make bigger and more detailed maps. I can add things like Source's env_fog_controller to let you control visibility (and add fog properly). Beyond that i can't say what you'll be able to do since i'm still working to implement the required components.

I'll try to explain the benefits of new features in simpler terms in the future so it's easier to understand.
Posted 6 years ago2018-08-11 19:23:04 UTC
in (Release) Half-Life: Echoes Post #340490
The engine only supports a maximum of 2048. Anything beyond that will crash the game if it tries to network an entity with an index >= 2048.
Posted 6 years ago2018-08-11 06:38:57 UTC
in (Release) Half-Life: Echoes Post #340480
Note that you can remove the need to launch through Steam by specifying the edicts count using the "edicts" liblist.gam key. This directly sets the edict count, rather than relying on commandargs. The greater of either "edicts" or "-num_edicts" will be used, but i'd recommend removing the commandargs version.
Posted 6 years ago2018-08-10 19:36:07 UTC
in (Release) Half-Life: Echoes Post #340474
Posted 6 years ago2018-08-10 12:59:32 UTC
in SharpLife - Dot Net Core based modding p Post #340469
I've added a table of engine components that are required and their status, it should make things a little easier to keep track of: https://github.com/SamVanheer/SharpLife-Engine/wiki/SharpLife-engine-components

I've been doing some experiments with making a good entity list design, since the one used in the SharpLife interop version wraps the original version.
I've come up with one that's pretty simple and efficient and that avoids global variables, so that part should be good to go once the networking system is done.
Posted 6 years ago2018-08-09 06:36:37 UTC
in SharpLife - Dot Net Core based modding p Post #340457
I looked into Alure, i don't think it's of much use in managed code since OpenTK already wraps the native API. I've built a basic program for playing sounds, it looks like it should be straightforward to use.

The only problems are that there is no file loading provided in the library itself and that there's stuttering on shutdown if the OpenTK AudioContext is disposed immediately after a sound has stopped playing. It only seems to happen with the wav test file i'm using (scientist/c1a0_sci_crit2a.wav from Half-Life), the mp3 file i tried (media/Half-Life11.mp3) didn't have that problem.

I can leverage other libraries to load various file types, so it's not that hard to implement.

I've also got a basic object list networking system up and running. I can serialize properties from an object to a stream and de-serialize them into another copy. It supports delta encoding and networking arbitrary length lists, as well as generics. It needs more work to be fully functional, but the important parts are working now.

Once the object list system is finished, i can implement a basic entity list and implement sky name settings. That should cover loading the BSP file itself, and once i've got the entity class hierarchy going i can put brush entities where they should be.

I've also committed the change to directly reference game assemblies in engine code, and i've merged what's left of the game config file (game name for display purposes) into the engine configuration.

I'm a bit busy with college work at the moment, so it'll be a few weeks before i can wrap these things up. Things are moving though, so it should work out.
The client and server are both performing the check so when the server's version is turned off, the client will switch between its locally predicted velocity and the server's actual velocity. That can't be fixed.
Posted 6 years ago2018-08-02 13:21:04 UTC
in SharpLife - Dot Net Core based modding p Post #340381
There are source files in the FMOD studio API installation that can be used to dllimport FMOD functions. I'm sure those are better maintained than any third party wrapper, but it seems that that wrapper is a more complete wrapper. I'll see which one's best for what's needed here.

I am going to change how SharpLife loads the game libraries so that it's hardcoded to the ones used now. This change is for the following reasons:
  1. The game libraries will be built as needed, without needing a manual build before running
  2. Modders should use distribute SharpLife as a whole mod, not as a mod for SharpLife
  3. The most important reason: the FMOD non-commercial license does not allowing distribution of the library in a game engine
To keep SharpLife as a mod and not an engine, the engine and game parts must remain tied together so that it counts as one entity.

This won't really affect modders since they'll want custom engine code anyway, and it'll simplify the code that accesses game code.

Edit: i discussed this with another programmer who has some experience with both FMOD and OpenAL and it seems that using OpenAL may be the better way to go here. FMOD's definition of a game engine fits SharpLife, even if it's running as a mod. OpenAL on the other hand has a modern and free implementation that has no licensing restrictions.

I found 2 C# wrappers that could be used:
https://github.com/flibitijibibo/OpenAL-CS
https://github.com/opentk/opentk

OpenTK is the more well known and used one, and both have .NET Core support.

At this point no code has been written yet, so the biggest issue is making sure it's all legal.

If anybody has any thoughts on the matter, i'd love to hear them. Audio support won't be required for some time, so we can figure this all out.

As far as reworking access to game code is concerned, i'll change that regardless to make things easier for everybody.
Valve implemented a check to prevent bunny hopping: https://github.com/ValveSoftware/halflife/blob/5d761709a31ce1e71488f2668321de05f791b405/pm_shared/pm_shared.c#L2433

Sven Co-op's codebase was never updated to use this.
Posted 6 years ago2018-08-01 15:12:19 UTC
in SharpLife - Dot Net Core based modding p Post #340361
I'm not going to worry about anything UI related for a while.

I've implemented network string lists. These are lists of strings that can be networked to clients. Any number of these can be created with any number of strings in them.
Once a string has been added, it cannot be modified or removed.

The purpose of these are to send large amounts of indexed strings to clients. For example, the model precache list is currently being sent this way.

New strings can be added at any time, and they will be sent to clients as well. This allows late precaching to be implemented.

One important feature is that every string can have binary data attached to it. This data comes in the form of Protobuf messages.
Every message type that you want to add to lists must first be registered so that it can be sent efficiently.

Different strings in the same list need not use the same binary data type, or any binary data at all.

Binary data can be changed at any time, which is useful when updating data. For example, you could send the map cycle and include basic information about it, such as how many players are required for the server to switch over to it. Another example is a map vote, and the current number of votes for each map.

You can add event handlers to respond to the adding of new strings on both the server and client, which can be useful to load models automatically when they're needed.

With this functionality being available, i can now implement proper resource precaching to enable the loading of the map as it should be, as well as loading other models and sprites. Adding support for sound precaching should also be simple.

On the subject of sound, i contacted Firelight Technologies about using FMOD, since their non-commercial license had some confusing wording. They gave me the green light to use FMOD in this project since it's non-commercial, which means there are no legal issues regarding the use of FMOD. I may implement a basic sound system soon to have that operational as well.

As far as networking goes, the only remaining major feature that requires implementing is networking objects. This requires a bit more work since this relies on delta encoding (sending only changes to the client), and i want to avoid hardcoding the engine's networking to an entity based system, so i'll probably come up with a generic system that can also be used to send any other list of objects to clients, whether using delta encoding or just sending the entire object.

That shouldn't be too difficult, and combined with C#'s reflection facilities it should be relatively straightforward to make classes serializable this way.

I'll begin working on object networking after i have a rudimentary entity system up and running in game code.
Posted 6 years ago2018-07-31 19:37:11 UTC
in SharpLife - Dot Net Core based modding p Post #340349
User posted image
I improved the console a bit so text can be selected. Auto scrolling doesn't work quite the way i want it; when text is added it will scroll the frame after it's been added because ImGui doesn't know the new content size yet, so it has to be delayed. This also means that a constant flow of text will delay scrolling by quite some time.

I've also reworked networking to make sure clients are fully disconnected before allowing them to connect again, and server shutdown and restarting with the map command works properly now.

I added in network message trace logging to help debug things, as well as logging state changes.

With that all done, i can now begin to work on networking the string lists. Once that's operational, i can add in the code to precache resources on both the client and server side (ideally using the same code).
Posted 6 years ago2018-07-29 20:54:38 UTC
in SharpLife - Dot Net Core based modding p Post #340325
User posted image
Added a console.
Posted 6 years ago2018-07-29 10:52:44 UTC
in SharpLife - Dot Net Core based modding p Post #340316
I've reworked the command system to make things a little safer and easier to use.

The old system worked mostly like the original: one command system that contains both server and client commands, where you could execute client commands when running a listen server, and where commands would be forwarded to the server as needed.

The new system separates the system into 3 pieces: the queue, contexts, and the overarching system.

The queue contains all commands to be executed. This works the same as it did before, only now you can only execute commands from the same context that your own command is being executed from.

A context contains a set of commands and aliases (defined with the alias command). There is a shared context whose commands are accessible from all contexts, but these commands can only execute commands that are in the context that this shared command is being executed from, so if you execute such a command from the client, it cannot execute server commands, but you can also execute the command from the server.

This helps protect against abuse by not allowing direct execution of arbitrary commands, but will not protect against things like slowhacking, which relies on servers being able to make the client insert commands into their local queue.

Command registration, queuing and execution remains the same, you won't notice any real difference in code. The big difference is that you no longer have to account for where a command comes from in the command handler, you are guaranteed that the command was either executed locally or was explicitly sent to from client to server or server to client.

This allowed me to remove the CommandSource enum, which was part of the original command system. It was a really inflexible way to detect if a command was forward to the server (needed so you can execute server commands from the client).
The new way to handle this, which isn't implemented yet is to use a helper to automatically forward these commands. You'd register a server command or variable, and register a client side forwarding command so the server can receive it.

The case where you're hosting a listen server and need to directly access server commands will probably be solved by adding an option to the console to switch to the server command context so you can directly perform server administration. Otherwise, you will need to use rcon to execute those commands.

An alternate option is to add a second input area for server specific commands.

Most cvar flags have been made obsolete with this change, of the 10 flags only half are still required at this time.
Further changes may make more of them obsolete in time.
Edit: Make that 3 required flags. The other 2 are now filters.

Edit 2: only 2 flags are part of the command system now, the third flag has been changed into a user defined flag since it's only used to save config cvars.
Commands can now have user defined flags added to them, so it can be flagged with specific boolean values.
In addition, commands can have tag objects associated with them to add arbitrary data to them. For instance, the map cycle cvar could store the map cycle manager object as a tag.
Posted 6 years ago2018-07-28 11:20:29 UTC
in SharpLife - Dot Net Core based modding p Post #340303
I've implemented a basic networking system now. Servers will set up networking, clients can connect to servers.

Message sending works up until the client receiving the message containing server info, including the map name, which it uses to load the BSP now.

In theory you could just launch with a different +map command to load any map, but i haven't tried that yet.

For those interested in seeing how much it takes to add a new message, these are the steps you have to take:
  • Make sure your dev environment is set up first by adding the path to protoc (Protobuf compiler) to your PATH environment variable. The tool is included in a NuGet package that's a dependency of the SharpLife.Networking.Shared library, so it will be located in your .nuget/packages directory. You can also download the tool from Google's Protobuf website
  • Create a .proto file in SharpLife.Networking.Shared.Messages (can be in a child namespace) containing your message definition, make sure to specify the package name
For example, here's the message that the server sends to the client to give it basic server info: https://github.com/SamVanheer/SharpLife-Engine/blob/23f235a39ca16423d35ab6007731d9df2a5c3f7f/src/SharpLife.Networking.Shared/Messages/Server/ServerInfo.proto
  • Rebuild SharpLife.Networking.Shared to automatically generate the message class. This is done using a pre-build step that executes a PowerShell script
You need to add the descriptor to the list, and adding new messages post-release should also come with a change to the protocol version constant: https://github.com/SamVanheer/SharpLife-Engine/blob/23f235a39ca16423d35ab6007731d9df2a5c3f7f/src/SharpLife.Networking.Shared/NetConstants.cs#L46

Depending on whether it's a server-to-client or client-to-server message you need to add it to either list.

The order of the messages is important, since it's used to generate the IDs used to identify incoming messages.
  • On the receiving side you'll need to register a handler:
https://github.com/SamVanheer/SharpLife-Engine/blob/23f235a39ca16423d35ab6007731d9df2a5c3f7f/src/SharpLife.Engine.Client/Host/EngineClientHost.Messages.cs#L40
https://github.com/SamVanheer/SharpLife-Engine/blob/23f235a39ca16423d35ab6007731d9df2a5c3f7f/src/SharpLife.Engine.Server/Host/EngineServerHost.Messages.cs#L38

Message handlers implement the IMessageReceiveHandler<TMessage> interface. TMessage is the class type of your message. The same class can implement multiple handlers. If a handler is not implemented, an exception will be thrown when a message for it is received.
  • That's about it. You can send messages pretty easily:
https://github.com/SamVanheer/SharpLife-Engine/blob/23f235a39ca16423d35ab6007731d9df2a5c3f7f/src/SharpLife.Engine.Client/Host/EngineClientHost.Messages.cs#L76
https://github.com/SamVanheer/SharpLife-Engine/blob/23f235a39ca16423d35ab6007731d9df2a5c3f7f/src/SharpLife.Engine.Server/Host/EngineServerHost.Messages.cs#L66

Adding a message will immediately add it to a list of outgoing messages and serializes it to a buffer. The message object is not kept after that.

Servers can send both reliable and unreliable data, to allow you to send non-critical data that can be lost or ignored without consequence (e.g. visual effect creation).

The engine will send messages automatically, but you can force the immediate sending of all pending data if you want. That's generally reserved for engine code that needs that done, and will not be exposed to game code.

Game code will also be able to register messages the same way, the only difference will be that message handlers will get an object that represents a client rather than a connection.

Note that the message IDs are internal and should never be used for any persistent uses. They can change easily and are normally handled entirely by the message transmission and dispatch systems. Unlike GoldSource, game messages won't require you to store off IDs, so you only have to make sure that your code uses the same list of message descriptors on the client and server.

There is currently no hard limit to the size of messages, but that will be needed to avoid issues later on.
The only hard limit is the number of clients, and that can easily be made a configuration variable.

SVC_BAD should not be possible with this system since message sizes are sent along, and messages are always parsed fully. Only malformed packets could cause it to happen.

Now the next things to do are:
  1. Build a simple UI to display the console and accept commands
  2. Implement a system to network arbitrary add-only string lists with binary data
The first is straightforward, i'll be implementing it in the game codebase so all UI code is there.

The second will take some doing. I'll have to look into a good way to network strings because sending them uncompressed could be a problem.
I don't want to just send whole lists at once, that could easily use a ton of memory and take a long time when there's packet drops happening.
Sending lists so each packet contains a self-contained section to process would be the best way to handle this. Whatever system i come up with should also be usable for game data networking to ensure that the client gets what it needs without having to wait to reassemble the packets containing the data.

The binary data will simply be Protobuf messages, it's the most efficient way to handle that.

Once that's done i can create a couple lists to store model, sound and generic precache data in them. Then i can implement proper resource precaching and let the client load everything up.

That's a fair amount of work, so i'll keep it at that for now.
Posted 6 years ago2018-07-28 10:56:38 UTC
in Coop Mod Post #340302
Of course, the other aspect of this is that, assuming we're still talking sticking as close to vanilla as possible, is that it still would be deathmatch at its core. I don't know how much coding it would require if you wanted to disable or restrict friendly fire, respawning, respawning ammo, etc.
You can disable friendly fire pretty easily: https://github.com/ValveSoftware/halflife/blob/5d761709a31ce1e71488f2668321de05f791b405/dlls/multiplay_gamerules.cpp#L527
if (pAttacker && pAttacker->IsPlayer())
{
    return FALSE;
}
Basically if the attacker is a player you ignore the damage. You could add a check here to see if the owner is a player (shouldn't be an issue unless a monster spawned by a player is doing damage) or do team checks instead.

You should probably create a new gamerules class though, otherwise it'll have all of the rules of regular deathmatch.
Posted 6 years ago2018-07-28 07:20:54 UTC
in Half-Life : Catastrophe Post #340297
https://discord.gg/8uyTp76

We're kind of missing an administrator though.