Steamworks.NET
Steamworks wrapper for Unity / C# (by rlabrecque)
GameTemplate
C# Godot game template with Steamworks.NET ready out-of-the-box. (by chickensoft-games)
Steamworks.NET | GameTemplate | |
---|---|---|
8 | 1 | |
2,579 | 25 | |
- | - | |
4.9 | 1.8 | |
about 2 months ago | about 2 years ago | |
C# | C# | |
MIT License | MIT License |
The number of mentions indicates the total number of mentions that we've tracked plus the number of user suggested alternatives.
Stars - the number of stars that a project has on GitHub. Growth - month over month growth in stars.
Activity is a relative number indicating how actively a project is being developed. Recent commits have higher weight than older ones.
For example, an activity of 9.0 indicates that a project is amongst the top 10% of the most actively developed projects that we are tracking.
Stars - the number of stars that a project has on GitHub. Growth - month over month growth in stars.
Activity is a relative number indicating how actively a project is being developed. Recent commits have higher weight than older ones.
For example, an activity of 9.0 indicates that a project is amongst the top 10% of the most actively developed projects that we are tracking.
Steamworks.NET
Posts with mentions or reviews of Steamworks.NET.
We have used some of these posts to build our list of alternatives
and similar projects. The last one was on 2022-03-13.
- How do you get more than four controllers to work with Steam Input and the new input system?
- Should I review my own game? (Still not published on Steam)
-
Networking solution for a turn based strategy in Unity?
You have a lot of options for networking (yes, the example you mentioned works well under peer-to-peer). I ended up using Steamworks.NET because it's pretty directly tied to the Steam SDK. It also let me match to my friends right on Steam (guessing you and your friends use it).
-
Photon Pun 2 Multiplayer Controlling the Same Player
using Photon.Pun; using Photon.Realtime; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; using Hashtable = ExitGames.Client.Photon.Hashtable; //Steamworks.Net repo - https://github.com/rlabrecque/Steamworks.NET.git?path=/com.rlabrecque.steamworks.net#20.1.0 public class PlayerController : MonoBehaviourPunCallbacks, IDamageable { [SerializeField] Image healthbarImage; [SerializeField] GameObject ui; [SerializeField] GameObject cameraHolder; [SerializeField] float mouseSensitivity, sprintSpeed, walkSpeed, jumpForce, smoothTime; public Slider sensSlider; public GameObject musicSource; [SerializeField] Item[] items; int itemIndex; int previousItemIndex = -1; float verticalLookRotation; Vector3 smoothMoveVelocity; Rigidbody rb; PhotonView PV; const float maxHealth = 100f; float currentHealth = maxHealth; PlayerManager playerManager; GunSystem gunSystem; public AudioSource damageSound; [Header("Movement")] private float moveSpeed; public float groundDrag; [Header("Jumping")] public float jumpCooldown; public float airMultiplier; bool readyToJump; [Header("Keybinds")] public KeyCode sprintKey = KeyCode.LeftShift; [Header("Ground Check")] public float playerHeight; public LayerMask whatIsGround; bool grounded; [Header("Slope Handling")] public float maxSlopeAngle; private RaycastHit slopeHit; private bool exitingSlope; public Transform orientation; float horizontalInput; float verticalInput; Vector3 moveDirection; public float slip; public float noSlip; Collider collider; public MovementState state; public enum MovementState { walking, sprinting, air } void Awake() { PV = GetComponent(); rb = GetComponent(); collider = GetComponent(); } void Start() { playerManager = PhotonView.Find((int)PV.InstantiationData[0]).GetComponent(); if (PV.IsMine) { EquipItem(0); } else { Destroy(GetComponentInChildren().gameObject); Destroy(rb); Destroy(ui); Destroy(musicSource); } readyToJump = true; mouseSensitivity = PlayerPrefs.GetFloat("Sensitivity", mouseSensitivity); sensSlider.value = mouseSensitivity; } void Update() { grounded = Physics.Raycast(transform.position, Vector3.down, playerHeight * 0.5f + 0.2f, whatIsGround); if(!Pause.isPaused) { MyInput(); } if(!PV.IsMine) { return; } else { if (grounded) rb.drag = groundDrag; else rb.drag = 0; } if(!PV.IsMine) return; if(!Pause.isPaused) { Look(); } for(int i = 0; i < items.Length; i++) { if(Input.GetKeyDown((i + 1).ToString())) { ResetItemIndex(); EquipItem(i); items[i].GetComponent().enabled = true; break; } } if(Input.GetAxisRaw("Mouse ScrollWheel") > 0f) { if(itemIndex >= items.Length - 1) { ResetItemIndex(); EquipItem(0); items[0].GetComponent().enabled = true; } else { ResetItemIndex(); EquipItem(itemIndex + 1); items[itemIndex].GetComponent().enabled = true; } } else if(Input.GetAxisRaw("Mouse ScrollWheel") < 0f) { if(itemIndex <= 0) { ResetItemIndex(); EquipItem(items.Length - 1); items[items.Length - 1].GetComponent().enabled = true; } else { ResetItemIndex(); EquipItem(itemIndex - 1); items[itemIndex].GetComponent().enabled = true; } } items[itemIndex].Use(); if(transform.position.y < -3f) // Die if you fall out of the world { Die(); } } void FixedUpdate() { if (!PV.IsMine) return; if(!Pause.isPaused) { SpeedControl(); StateHandler(); MovePlayer(); NoSlip(); } } private void Look() { if (!PV.IsMine) return; transform.Rotate(Vector3.up * Input.GetAxisRaw("Mouse X") * mouseSensitivity); verticalLookRotation += Input.GetAxisRaw("Mouse Y") * mouseSensitivity; verticalLookRotation = Mathf.Clamp(verticalLookRotation, -90f, 90f); cameraHolder.transform.localEulerAngles = Vector3.left * verticalLookRotation; } private void MyInput() { if (!PV.IsMine) return; horizontalInput = Input.GetAxisRaw("Horizontal"); verticalInput = Input.GetAxisRaw("Vertical"); // when to jump if(Input.GetButtonDown("Jump") && readyToJump && grounded) { readyToJump = false; Jump(); Invoke(nameof(ResetJump), jumpCooldown); } } void NoSlip() { if(rb.velocity.x == 0 && rb.velocity.y == 0 && rb.velocity.z == 0) { collider.material.dynamicFriction = noSlip; collider.material.staticFriction = noSlip; } else { collider.material.dynamicFriction = slip; collider.material.staticFriction = slip; } } private void StateHandler() { // Mode - Sprinting if(grounded && Input.GetKey(sprintKey) || Input.GetButton("XBOX_LJP")) { state = MovementState.sprinting; moveSpeed = sprintSpeed; } // Mode - Walking else if (grounded) { state = MovementState.walking; moveSpeed = walkSpeed; } // Mode - Air else { state = MovementState.air; } } private void MovePlayer() { // calculate movement direction moveDirection = orientation.forward * verticalInput + orientation.right * horizontalInput; // on slope if (OnSlope() && !exitingSlope) { rb.AddForce(GetSlopeMoveDirection() * moveSpeed * 20f, ForceMode.Force); if (rb.velocity.y > 0) rb.AddForce(Vector3.down * 80f, ForceMode.Force); } // on ground else if(grounded) rb.AddForce(moveDirection.normalized * moveSpeed * 10f, ForceMode.Force); // in air else if(!grounded) rb.AddForce(moveDirection.normalized * moveSpeed * 10f * airMultiplier, ForceMode.Force); // turn gravity off while on slope rb.useGravity = !OnSlope(); } private void SpeedControl() { // limiting speed on slope if (OnSlope() && !exitingSlope) { if (rb.velocity.magnitude > moveSpeed) rb.velocity = rb.velocity.normalized * moveSpeed; } // limiting speed on ground or in air else { Vector3 flatVel = new Vector3(rb.velocity.x, 0f, rb.velocity.z); // limit velocity if needed if (flatVel.magnitude > moveSpeed) { Vector3 limitedVel = flatVel.normalized * moveSpeed; rb.velocity = new Vector3(limitedVel.x, rb.velocity.y, limitedVel.z); } } } private void Jump() { exitingSlope = true; // reset y velocity rb.velocity = new Vector3(rb.velocity.x, 0f, rb.velocity.z); rb.AddForce(transform.up * jumpForce, ForceMode.Impulse); } private void ResetJump() { readyToJump = true; exitingSlope = false; } private bool OnSlope() { if(Physics.Raycast(transform.position, Vector3.down, out slopeHit, playerHeight * 0.5f + 0.3f)) { float angle = Vector3.Angle(Vector3.up, slopeHit.normal); return angle < maxSlopeAngle && angle != 0; } return false; } private Vector3 GetSlopeMoveDirection() { return Vector3.ProjectOnPlane(moveDirection, slopeHit.normal).normalized; } void EquipItem(int _index) { if(_index == previousItemIndex) return; itemIndex = _index; items[itemIndex].itemGameObject.SetActive(true); if(previousItemIndex != -1) { items[previousItemIndex].itemGameObject.SetActive(false); } previousItemIndex = itemIndex; if(PV.IsMine) { Hashtable hash = new Hashtable(); hash.Add("itemIndex", itemIndex); PhotonNetwork.LocalPlayer.SetCustomProperties(hash); } } public override void OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps) { if(!PV.IsMine && targetPlayer == PV.Owner) { EquipItem((int)changedProps["itemIndex"]); } } public void TakeDamage(float damage) { PV.RPC("RPC_TakeDamage", RpcTarget.All, damage); } [PunRPC] void RPC_TakeDamage(float damage) { if(!PV.IsMine) return; damageSound.Play(); currentHealth -= damage; healthbarImage.fillAmount = currentHealth / maxHealth; if(currentHealth <= 0) { Die(); } } void Die() { playerManager.Die(); } public void Sensitivity() { mouseSensitivity = sensSlider.value; PlayerPrefs.SetFloat("Sensitivity", mouseSensitivity); } void ResetItemIndex() { for (int j = 0; j < items.Length; j++) { items[j].GetComponent().enabled = false; } } }
-
Steamworks multiplayer - Godot vs Unity
I have a multiplayer game on steam made with Godot C# and Steamworks.NET wrapper https://steamworks.github.io/.
-
Steamworks.NET issue with "ExchangeItems"
Hi, I am using Steamworks.NET for my game, I'm near releasing it and I have an issue. I use the "ExchangeItems" function for my game so players can earn cosmetics, The function consumes the crate (that the player opens), and the output is a generator with a bundle. The issue/error I get is: k_EResultFail, and the crate doesn't get consumed and I don't earn any items.
-
I made a C# Steamworks.NET Template for macOS and Windows
I put together a repository you can borrow if you want to make a C# Godot game that uses Steamworks.NET on either Mac or Windows.
-
How do you create a game with Steam Workshop in mind?
Also, C# wrapper https://github.com/rlabrecque/Steamworks.NET
GameTemplate
Posts with mentions or reviews of GameTemplate.
We have used some of these posts to build our list of alternatives
and similar projects. The last one was on 2022-03-13.
-
I made a C# Steamworks.NET Template for macOS and Windows
I put together a repository you can borrow if you want to make a C# Godot game that uses Steamworks.NET on either Mac or Windows.
What are some alternatives?
When comparing Steamworks.NET and GameTemplate you can also consider the following projects:
Facepunch.Steamworks - Another fucking c# Steamworks implementation
Steamworks.NET-Test - Test project for Steamworks.NET
MasterMemory - Embedded Typed Readonly In-Memory Document Database for .NET and Unity.
MessagePack for C# (.NET, .NET Core, Unity, Xamarin) - Extremely Fast MessagePack Serializer for C#(.NET, .NET Core, Unity, Xamarin). / msgpack.org[C#]
ILSpy - .NET Decompiler with support for PDB generation, ReadyToRun, Metadata (&more) - cross-platform!