Steamworks.NET
Facepunch.Steamworks
Steamworks.NET | Facepunch.Steamworks | |
---|---|---|
8 | 9 | |
2,573 | 2,721 | |
- | 0.8% | |
4.9 | 2.5 | |
about 2 months ago | 21 days ago | |
C# | C# | |
MIT License | MIT License |
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
- 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
Facepunch.Steamworks
-
How to get voicechat working with Facepunch.Steamworks
This link might help as it has a couple examples: https://github.com/Facepunch/Facepunch.Steamworks/issues/261
-
How would a non-AAA company deliver multiplayer, or even online stuff like leaderboards?
- I'm using Facepunch as the steam library - it's a nice wrapper around the steam SDK, which can be a little annoying to use directly.
-
How should I approach adding multiplayer to my game? Considering the economy and attractiveness of multiplayer games.
If you are using Unity, have a look at the facepunch wrapper for the Steamworks SDK. It's pretty nice.
-
What do you guys use for networking with Steam (P2P)?
I’ve been using this. Very easy to use, has p2p support. https://github.com/Facepunch/Facepunch.Steamworks
-
I made a C# Steamworks.NET Template for macOS and Windows
I also tried to integrate Facepunch.Steamworks, but it didn't seem to be working on Apple Silicon (if I understand correctly). Facepunch's last release was also 2 years ago. Since the latest Steamworks.NET was released a month ago, I believe it's currently the way to go (despite the clunkier API) if you're trying to integrate Steam into your C# Godot Project.
-
FizzyFacepunch issue
Facepunch.Steamworks 2.3.2
-
Developer of Crab Game recommends streamers to "stay away from public lobbies for a few days" as he works on the DDoS issue
Steam's latest networking API has built in support for using relays to hide p2p IP addresses. He was using Another Fucking Steamworks C# Implementation which appears to be based on the older network apis.
- 3 months of solo game development progress in 40 seconds. Hope you enjoy!
-
Distributing DLC through Steam
Depending on how you check various things, I'd recommend you use Facepunch.Steamworks which is free and available here: https://github.com/Facepunch/Facepunch.Steamworks
What are some alternatives?
Steamworks.NET-Test - Test project for Steamworks.NET
FizzyFacepunch - A transport for Mirror using Steam / Facepunch
MasterMemory - Embedded Typed Readonly In-Memory Document Database for .NET and Unity.
GameTemplate - C# Godot game template with Steamworks.NET ready out-of-the-box.
MelonLoader - The World's First Universal Mod Loader for Unity Games compatible with both Il2Cpp and Mono
MessagePack for C# (.NET, .NET Core, Unity, Xamarin) - Extremely Fast MessagePack Serializer for C#(.NET, .NET Core, Unity, Xamarin). / msgpack.org[C#]
YarnSpinner - Yarn Spinner is a tool for building interactive dialogue in games!
ILSpy - .NET Decompiler with support for PDB generation, ReadyToRun, Metadata (&more) - cross-platform!
Card-Game-Simulator - Create, Share, and Play
Zenject - Dependency Injection Framework for Unity3D
open-project-1 - Unity Open Project #1: Chop Chop