Adding Gold Manager with initial network setup
This commit is contained in:
parent
048e618f1e
commit
9369763df5
15 changed files with 488 additions and 100 deletions
6
.vsconfig
Normal file
6
.vsconfig
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"version": "1.0",
|
||||||
|
"components": [
|
||||||
|
"Microsoft.VisualStudio.Workload.ManagedGame"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -38,12 +38,12 @@ RenderSettings:
|
||||||
m_ReflectionIntensity: 1
|
m_ReflectionIntensity: 1
|
||||||
m_CustomReflection: {fileID: 0}
|
m_CustomReflection: {fileID: 0}
|
||||||
m_Sun: {fileID: 0}
|
m_Sun: {fileID: 0}
|
||||||
m_IndirectSpecularColor: {r: 0.18028378, g: 0.22571412, b: 0.30692285, a: 1}
|
|
||||||
m_UseRadianceAmbientProbe: 0
|
m_UseRadianceAmbientProbe: 0
|
||||||
--- !u!157 &3
|
--- !u!157 &3
|
||||||
LightmapSettings:
|
LightmapSettings:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
serializedVersion: 12
|
serializedVersion: 13
|
||||||
|
m_BakeOnSceneLoad: 0
|
||||||
m_GISettings:
|
m_GISettings:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
m_BounceScale: 1
|
m_BounceScale: 1
|
||||||
|
|
@ -119,6 +119,78 @@ NavMeshSettings:
|
||||||
debug:
|
debug:
|
||||||
m_Flags: 0
|
m_Flags: 0
|
||||||
m_NavMeshData: {fileID: 0}
|
m_NavMeshData: {fileID: 0}
|
||||||
|
--- !u!1 &239104687
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 239104690}
|
||||||
|
- component: {fileID: 239104688}
|
||||||
|
- component: {fileID: 239104689}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: GoldManager
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!114 &239104688
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 239104687}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.NetworkObject
|
||||||
|
GlobalObjectIdHash: 3224213014
|
||||||
|
InScenePlacedSourceGlobalObjectIdHash: 0
|
||||||
|
DeferredDespawnTick: 0
|
||||||
|
Ownership: 1
|
||||||
|
AlwaysReplicateAsRoot: 0
|
||||||
|
SynchronizeTransform: 1
|
||||||
|
ActiveSceneSynchronization: 0
|
||||||
|
SceneMigrationSynchronization: 0
|
||||||
|
SpawnWithObservers: 1
|
||||||
|
DontDestroyWithOwner: 0
|
||||||
|
AutoObjectParentSync: 1
|
||||||
|
SyncOwnerTransformWhenParented: 1
|
||||||
|
AllowOwnerToParent: 0
|
||||||
|
--- !u!114 &239104689
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 239104687}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: d44ebdd0b2fc4144c8f8a181a714b738, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.GoldManager
|
||||||
|
ShowTopMostFoldoutHeaderGroup: 1
|
||||||
|
startingGold: 100
|
||||||
|
--- !u!4 &239104690
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 239104687}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
--- !u!1 &330585543
|
--- !u!1 &330585543
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|
@ -248,14 +320,14 @@ MonoBehaviour:
|
||||||
m_ScreenCoordScaleBias: {x: 0, y: 0, z: 0, w: 0}
|
m_ScreenCoordScaleBias: {x: 0, y: 0, z: 0, w: 0}
|
||||||
m_RequiresDepthTexture: 0
|
m_RequiresDepthTexture: 0
|
||||||
m_RequiresColorTexture: 0
|
m_RequiresColorTexture: 0
|
||||||
m_Version: 2
|
|
||||||
m_TaaSettings:
|
m_TaaSettings:
|
||||||
quality: 3
|
m_Quality: 3
|
||||||
frameInfluence: 0.1
|
m_FrameInfluence: 0.1
|
||||||
jitterScale: 1
|
m_JitterScale: 1
|
||||||
mipBias: 0
|
m_MipBias: 0
|
||||||
varianceClampScale: 0.9
|
m_VarianceClampScale: 0.9
|
||||||
contrastAdaptiveSharpening: 0
|
m_ContrastAdaptiveSharpening: 0
|
||||||
|
m_Version: 2
|
||||||
--- !u!1 &410087039
|
--- !u!1 &410087039
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|
@ -282,14 +354,14 @@ Light:
|
||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
m_GameObject: {fileID: 410087039}
|
m_GameObject: {fileID: 410087039}
|
||||||
m_Enabled: 1
|
m_Enabled: 1
|
||||||
serializedVersion: 11
|
serializedVersion: 13
|
||||||
m_Type: 1
|
m_Type: 1
|
||||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||||
m_Intensity: 2
|
m_Intensity: 2
|
||||||
m_Range: 10
|
m_Range: 10
|
||||||
m_SpotAngle: 30
|
m_SpotAngle: 30
|
||||||
m_InnerSpotAngle: 21.80208
|
m_InnerSpotAngle: 21.80208
|
||||||
m_CookieSize: 10
|
m_CookieSize2D: {x: 10, y: 10}
|
||||||
m_Shadows:
|
m_Shadows:
|
||||||
m_Type: 2
|
m_Type: 2
|
||||||
m_Resolution: -1
|
m_Resolution: -1
|
||||||
|
|
@ -334,8 +406,11 @@ Light:
|
||||||
m_UseBoundingSphereOverride: 0
|
m_UseBoundingSphereOverride: 0
|
||||||
m_UseViewFrustumForShadowCasterCull: 1
|
m_UseViewFrustumForShadowCasterCull: 1
|
||||||
m_ForceVisible: 0
|
m_ForceVisible: 0
|
||||||
m_ShadowRadius: 0
|
m_ShapeRadius: 0
|
||||||
m_ShadowAngle: 0
|
m_ShadowAngle: 0
|
||||||
|
m_LightUnit: 1
|
||||||
|
m_LuxAtDistance: 1
|
||||||
|
m_EnableSpotReflector: 1
|
||||||
--- !u!4 &410087041
|
--- !u!4 &410087041
|
||||||
Transform:
|
Transform:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|
@ -363,17 +438,23 @@ MonoBehaviour:
|
||||||
m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3}
|
m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
m_Version: 3
|
|
||||||
m_UsePipelineSettings: 1
|
m_UsePipelineSettings: 1
|
||||||
m_AdditionalLightsShadowResolutionTier: 2
|
m_AdditionalLightsShadowResolutionTier: 2
|
||||||
m_LightLayerMask: 1
|
|
||||||
m_RenderingLayers: 1
|
|
||||||
m_CustomShadowLayers: 0
|
m_CustomShadowLayers: 0
|
||||||
m_ShadowLayerMask: 1
|
|
||||||
m_ShadowRenderingLayers: 1
|
|
||||||
m_LightCookieSize: {x: 1, y: 1}
|
m_LightCookieSize: {x: 1, y: 1}
|
||||||
m_LightCookieOffset: {x: 0, y: 0}
|
m_LightCookieOffset: {x: 0, y: 0}
|
||||||
m_SoftShadowQuality: 1
|
m_SoftShadowQuality: 1
|
||||||
|
m_RenderingLayersMask:
|
||||||
|
serializedVersion: 0
|
||||||
|
m_Bits: 1
|
||||||
|
m_ShadowRenderingLayersMask:
|
||||||
|
serializedVersion: 0
|
||||||
|
m_Bits: 1
|
||||||
|
m_Version: 4
|
||||||
|
m_LightLayerMask: 1
|
||||||
|
m_ShadowLayerMask: 1
|
||||||
|
m_RenderingLayers: 1
|
||||||
|
m_ShadowRenderingLayers: 1
|
||||||
--- !u!1 &832575517
|
--- !u!1 &832575517
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|
@ -423,6 +504,112 @@ Transform:
|
||||||
m_Children: []
|
m_Children: []
|
||||||
m_Father: {fileID: 0}
|
m_Father: {fileID: 0}
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!1 &1682341399
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 1682341402}
|
||||||
|
- component: {fileID: 1682341401}
|
||||||
|
- component: {fileID: 1682341400}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: NetworkManager
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!114 &1682341400
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1682341399}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 6960e84d07fb87f47956e7a81d71c4e6, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.Transports.UTP.UnityTransport
|
||||||
|
m_ProtocolType: 0
|
||||||
|
m_UseWebSockets: 0
|
||||||
|
m_UseEncryption: 0
|
||||||
|
m_MaxPacketQueueSize: 128
|
||||||
|
m_MaxPayloadSize: 6144
|
||||||
|
m_HeartbeatTimeoutMS: 500
|
||||||
|
m_ConnectTimeoutMS: 1000
|
||||||
|
m_MaxConnectAttempts: 60
|
||||||
|
m_DisconnectTimeoutMS: 30000
|
||||||
|
ConnectionData:
|
||||||
|
Address: 127.0.0.1
|
||||||
|
Port: 7777
|
||||||
|
WebSocketPath: /
|
||||||
|
ServerListenAddress: 127.0.0.1
|
||||||
|
ClientBindPort: 0
|
||||||
|
DebugSimulator:
|
||||||
|
PacketDelayMS: 0
|
||||||
|
PacketJitterMS: 0
|
||||||
|
PacketDropRate: 0
|
||||||
|
--- !u!114 &1682341401
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1682341399}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 593a2fe42fa9d37498c96f9a383b6521, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.NetworkManager
|
||||||
|
NetworkManagerExpanded: 0
|
||||||
|
NetworkConfig:
|
||||||
|
ProtocolVersion: 0
|
||||||
|
NetworkTransport: {fileID: 1682341400}
|
||||||
|
PlayerPrefab: {fileID: 0}
|
||||||
|
Prefabs:
|
||||||
|
NetworkPrefabsLists:
|
||||||
|
- {fileID: 11400000, guid: 481ab1d7456efd044bc3e349aacd92ae, type: 2}
|
||||||
|
TickRate: 30
|
||||||
|
ClientConnectionBufferTimeout: 10
|
||||||
|
ConnectionApproval: 0
|
||||||
|
ConnectionData:
|
||||||
|
EnableTimeResync: 0
|
||||||
|
TimeResyncInterval: 30
|
||||||
|
EnsureNetworkVariableLengthSafety: 0
|
||||||
|
EnableSceneManagement: 1
|
||||||
|
ForceSamePrefabs: 1
|
||||||
|
RecycleNetworkIds: 1
|
||||||
|
NetworkIdRecycleDelay: 120
|
||||||
|
RpcHashSize: 0
|
||||||
|
LoadSceneTimeOut: 120
|
||||||
|
SpawnTimeout: 10
|
||||||
|
EnableNetworkLogs: 1
|
||||||
|
NetworkTopology: 0
|
||||||
|
UseCMBService: 0
|
||||||
|
AutoSpawnPlayerPrefabClientSide: 1
|
||||||
|
NetworkProfilingMetrics: 1
|
||||||
|
OldPrefabList: []
|
||||||
|
RunInBackground: 1
|
||||||
|
LogLevel: 1
|
||||||
|
--- !u!4 &1682341402
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1682341399}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
--- !u!1660057539 &9223372036854775807
|
--- !u!1660057539 &9223372036854775807
|
||||||
SceneRoots:
|
SceneRoots:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|
@ -430,3 +617,5 @@ SceneRoots:
|
||||||
- {fileID: 330585546}
|
- {fileID: 330585546}
|
||||||
- {fileID: 410087041}
|
- {fileID: 410087041}
|
||||||
- {fileID: 832575519}
|
- {fileID: 832575519}
|
||||||
|
- {fileID: 1682341402}
|
||||||
|
- {fileID: 239104690}
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
{
|
|
||||||
"name": "TD.Core"
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
fileFormatVersion: 2
|
|
||||||
guid: f62380d35dc31494f957f6b5559755f5
|
|
||||||
AssemblyDefinitionImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
152
Assets/_Project/Scripts/Gameplay/GoldManager.cs
Normal file
152
Assets/_Project/Scripts/Gameplay/GoldManager.cs
Normal file
|
|
@ -0,0 +1,152 @@
|
||||||
|
using Unity.Netcode;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace TD.Gameplay
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// GoldManager — canonical server-authoritative template for this project.
|
||||||
|
///
|
||||||
|
/// Every gameplay system (towers, enemies, waves, damage) should follow
|
||||||
|
/// the same three-beat pattern demonstrated here:
|
||||||
|
/// 1. State lives in NetworkVariables, which only the server can write.
|
||||||
|
/// 2. Clients REQUEST changes via [Rpc(SendTo.Server, ...)] methods.
|
||||||
|
/// They never change state directly.
|
||||||
|
/// 3. The server VALIDATES the request before applying it.
|
||||||
|
/// Never trust the client.
|
||||||
|
///
|
||||||
|
/// Cosmetic-only reactions (sounds, VFX, UI popups) can use
|
||||||
|
/// [Rpc(SendTo.ClientsAndHost)] or [Rpc(SendTo.NotServer)] to broadcast.
|
||||||
|
/// </summary>
|
||||||
|
public class GoldManager : NetworkBehaviour
|
||||||
|
{
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
Debug.Log("[GoldManager] Awake ran!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Tunables (editable in Inspector) -----------------------------
|
||||||
|
|
||||||
|
[Tooltip("How much gold every player starts with when the game begins.")]
|
||||||
|
[SerializeField] private int startingGold = 100;
|
||||||
|
|
||||||
|
// --- Networked state ----------------------------------------------
|
||||||
|
|
||||||
|
// A NetworkVariable<T> automatically syncs from server to clients.
|
||||||
|
// readPerm = Everyone: all clients can read the current value.
|
||||||
|
// writePerm = Server: only the server can change it.
|
||||||
|
private readonly NetworkVariable<int> currentGold = new NetworkVariable<int>(
|
||||||
|
value: 0,
|
||||||
|
readPerm: NetworkVariableReadPermission.Everyone,
|
||||||
|
writePerm: NetworkVariableWritePermission.Server
|
||||||
|
);
|
||||||
|
|
||||||
|
// Public read-only accessor for other scripts (UI, tower placement).
|
||||||
|
public int CurrentGold => currentGold.Value;
|
||||||
|
|
||||||
|
// --- Lifecycle ----------------------------------------------------
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// OnNetworkSpawn runs on every peer (server + all clients) when this
|
||||||
|
/// NetworkBehaviour becomes active on the network. Replaces Start()
|
||||||
|
/// for networked setup.
|
||||||
|
/// </summary>
|
||||||
|
public override void OnNetworkSpawn()
|
||||||
|
{
|
||||||
|
Debug.Log($"[GoldManager] OnNetworkSpawn ran. IsServer={IsServer}, IsClient={IsClient}, IsHost={IsHost}");
|
||||||
|
|
||||||
|
currentGold.OnValueChanged += HandleGoldChanged;
|
||||||
|
Debug.Log($"[GoldManager] Subscribed to OnValueChanged. Current value before init: {currentGold.Value}");
|
||||||
|
|
||||||
|
if (IsServer)
|
||||||
|
{
|
||||||
|
currentGold.Value = startingGold;
|
||||||
|
Debug.Log($"[GoldManager] Server initialized gold. Current value after set: {currentGold.Value}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnNetworkDespawn()
|
||||||
|
{
|
||||||
|
// Always unsubscribe to avoid callback leaks.
|
||||||
|
currentGold.OnValueChanged -= HandleGoldChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleGoldChanged(int previous, int current)
|
||||||
|
{
|
||||||
|
// Fires on every peer whenever the value syncs. Use Log here so
|
||||||
|
// you can see syncing in the Console during development.
|
||||||
|
Debug.Log($"[GoldManager] Gold changed: {previous} -> {current}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Public API (called by client-side code) ----------------------
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Client-side entry point for spending gold. Called by gameplay code
|
||||||
|
/// like TowerPlacement when the local player clicks "build tower."
|
||||||
|
///
|
||||||
|
/// The actual spending happens on the server via the Rpc.
|
||||||
|
/// </summary>
|
||||||
|
public void RequestSpendGold(int amount)
|
||||||
|
{
|
||||||
|
SpendGoldRpc(amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Server-side entry point for awarding gold (wave clear, enemy kill).
|
||||||
|
/// Not Rpc-wrapped — this is called directly by server game logic in
|
||||||
|
/// response to server-authoritative events.
|
||||||
|
/// </summary>
|
||||||
|
public void AwardGold(int amount)
|
||||||
|
{
|
||||||
|
if (!IsServer)
|
||||||
|
{
|
||||||
|
Debug.LogError("[GoldManager] AwardGold called on a client! " +
|
||||||
|
"Only server code should call this directly.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (amount <= 0) return;
|
||||||
|
currentGold.Value += amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Server-side RPC ----------------------------------------------
|
||||||
|
|
||||||
|
// [Rpc(SendTo.Server, ...)] means: a client calls this locally, but
|
||||||
|
// NGO routes the call and executes the method on the server.
|
||||||
|
//
|
||||||
|
// RequireOwnership = false lets any client call it (correct for a
|
||||||
|
// shared GoldManager). For per-player NetworkObjects you'd usually
|
||||||
|
// leave the default ownership requirement in place.
|
||||||
|
//
|
||||||
|
// Naming convention: methods with [Rpc] attributes must end with "Rpc".
|
||||||
|
// The source generator relies on this suffix.
|
||||||
|
[Rpc(SendTo.Server, RequireOwnership = false)]
|
||||||
|
private void SpendGoldRpc(int amount, RpcParams rpcParams = default)
|
||||||
|
{
|
||||||
|
// This method body runs on the server only.
|
||||||
|
// Validate everything — do not trust the client.
|
||||||
|
|
||||||
|
// Validation 1: reject non-positive amounts. A negative amount
|
||||||
|
// would let a malicious client GAIN gold if we just subtracted.
|
||||||
|
if (amount <= 0)
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"[GoldManager] Rejected spend of {amount} " +
|
||||||
|
$"from client {rpcParams.Receive.SenderClientId}: " +
|
||||||
|
$"amount must be positive.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validation 2: can't spend more than current balance.
|
||||||
|
if (currentGold.Value < amount)
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"[GoldManager] Rejected spend of {amount} " +
|
||||||
|
$"from client {rpcParams.Receive.SenderClientId}: " +
|
||||||
|
$"insufficient funds (have {currentGold.Value}).");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server applies the change. NetworkVariable syncs to clients
|
||||||
|
// automatically at the next network tick.
|
||||||
|
currentGold.Value -= amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Assets/_Project/Scripts/Gameplay/GoldManager.cs.meta
Normal file
2
Assets/_Project/Scripts/Gameplay/GoldManager.cs.meta
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d44ebdd0b2fc4144c8f8a181a714b738
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
{
|
|
||||||
"name": "TD.Gameplay",
|
|
||||||
"rootNamespace": "",
|
|
||||||
"references": [
|
|
||||||
"GUID:f62380d35dc31494f957f6b5559755f5"
|
|
||||||
],
|
|
||||||
"includePlatforms": [],
|
|
||||||
"excludePlatforms": [],
|
|
||||||
"allowUnsafeCode": false,
|
|
||||||
"overrideReferences": false,
|
|
||||||
"precompiledReferences": [],
|
|
||||||
"autoReferenced": true,
|
|
||||||
"defineConstraints": [],
|
|
||||||
"versionDefines": [],
|
|
||||||
"noEngineReferences": false
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
fileFormatVersion: 2
|
|
||||||
guid: 027bbe8f3a58f024fa5c3fd977f0371b
|
|
||||||
AssemblyDefinitionImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
{
|
|
||||||
"name": "TD.Networking",
|
|
||||||
"rootNamespace": "",
|
|
||||||
"references": [
|
|
||||||
"GUID:f62380d35dc31494f957f6b5559755f5",
|
|
||||||
"GUID:027bbe8f3a58f024fa5c3fd977f0371b",
|
|
||||||
"GUID:1491147abca9d7d4bb7105af628b223e"
|
|
||||||
],
|
|
||||||
"includePlatforms": [],
|
|
||||||
"excludePlatforms": [],
|
|
||||||
"allowUnsafeCode": false,
|
|
||||||
"overrideReferences": false,
|
|
||||||
"precompiledReferences": [],
|
|
||||||
"autoReferenced": true,
|
|
||||||
"defineConstraints": [],
|
|
||||||
"versionDefines": [],
|
|
||||||
"noEngineReferences": false
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
fileFormatVersion: 2
|
|
||||||
guid: 824f8ff8ddfcf9a4da4b9c38a264d73e
|
|
||||||
AssemblyDefinitionImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
{
|
|
||||||
"name": "TD.UI",
|
|
||||||
"rootNamespace": "",
|
|
||||||
"references": [
|
|
||||||
"GUID:027bbe8f3a58f024fa5c3fd977f0371b",
|
|
||||||
"GUID:f62380d35dc31494f957f6b5559755f5"
|
|
||||||
],
|
|
||||||
"includePlatforms": [],
|
|
||||||
"excludePlatforms": [],
|
|
||||||
"allowUnsafeCode": false,
|
|
||||||
"overrideReferences": false,
|
|
||||||
"precompiledReferences": [],
|
|
||||||
"autoReferenced": true,
|
|
||||||
"defineConstraints": [],
|
|
||||||
"versionDefines": [],
|
|
||||||
"noEngineReferences": false
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
fileFormatVersion: 2
|
|
||||||
guid: dccb24d2a739b9d46aa3fc7d50c9511e
|
|
||||||
AssemblyDefinitionImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
|
|
@ -6,7 +6,7 @@ EditorBuildSettings:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
m_Scenes:
|
m_Scenes:
|
||||||
- enabled: 1
|
- enabled: 1
|
||||||
path: Assets/_Project/Scenes/SampleScene.unity
|
path: Assets/_Project/Scenes/Levels/Main.unity
|
||||||
guid: 99c9720ab356a0642a771bea13969a05
|
guid: 99c9720ab356a0642a771bea13969a05
|
||||||
m_configObjects:
|
m_configObjects:
|
||||||
com.unity.input.settings.actions: {fileID: -944628639613478452, guid: 052faaac586de48259a63d0c4782560b, type: 3}
|
com.unity.input.settings.actions: {fileID: -944628639613478452, guid: 052faaac586de48259a63d0c4782560b, type: 3}
|
||||||
|
|
|
||||||
121
ProjectSettings/SceneTemplateSettings.json
Normal file
121
ProjectSettings/SceneTemplateSettings.json
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
{
|
||||||
|
"templatePinStates": [],
|
||||||
|
"dependencyTypeInfos": [
|
||||||
|
{
|
||||||
|
"userAdded": false,
|
||||||
|
"type": "UnityEngine.AnimationClip",
|
||||||
|
"defaultInstantiationMode": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"userAdded": false,
|
||||||
|
"type": "UnityEditor.Animations.AnimatorController",
|
||||||
|
"defaultInstantiationMode": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"userAdded": false,
|
||||||
|
"type": "UnityEngine.AnimatorOverrideController",
|
||||||
|
"defaultInstantiationMode": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"userAdded": false,
|
||||||
|
"type": "UnityEditor.Audio.AudioMixerController",
|
||||||
|
"defaultInstantiationMode": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"userAdded": false,
|
||||||
|
"type": "UnityEngine.ComputeShader",
|
||||||
|
"defaultInstantiationMode": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"userAdded": false,
|
||||||
|
"type": "UnityEngine.Cubemap",
|
||||||
|
"defaultInstantiationMode": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"userAdded": false,
|
||||||
|
"type": "UnityEngine.GameObject",
|
||||||
|
"defaultInstantiationMode": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"userAdded": false,
|
||||||
|
"type": "UnityEditor.LightingDataAsset",
|
||||||
|
"defaultInstantiationMode": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"userAdded": false,
|
||||||
|
"type": "UnityEngine.LightingSettings",
|
||||||
|
"defaultInstantiationMode": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"userAdded": false,
|
||||||
|
"type": "UnityEngine.Material",
|
||||||
|
"defaultInstantiationMode": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"userAdded": false,
|
||||||
|
"type": "UnityEditor.MonoScript",
|
||||||
|
"defaultInstantiationMode": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"userAdded": false,
|
||||||
|
"type": "UnityEngine.PhysicsMaterial",
|
||||||
|
"defaultInstantiationMode": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"userAdded": false,
|
||||||
|
"type": "UnityEngine.PhysicsMaterial2D",
|
||||||
|
"defaultInstantiationMode": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"userAdded": false,
|
||||||
|
"type": "UnityEngine.Rendering.PostProcessing.PostProcessProfile",
|
||||||
|
"defaultInstantiationMode": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"userAdded": false,
|
||||||
|
"type": "UnityEngine.Rendering.PostProcessing.PostProcessResources",
|
||||||
|
"defaultInstantiationMode": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"userAdded": false,
|
||||||
|
"type": "UnityEngine.Rendering.VolumeProfile",
|
||||||
|
"defaultInstantiationMode": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"userAdded": false,
|
||||||
|
"type": "UnityEditor.SceneAsset",
|
||||||
|
"defaultInstantiationMode": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"userAdded": false,
|
||||||
|
"type": "UnityEngine.Shader",
|
||||||
|
"defaultInstantiationMode": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"userAdded": false,
|
||||||
|
"type": "UnityEngine.ShaderVariantCollection",
|
||||||
|
"defaultInstantiationMode": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"userAdded": false,
|
||||||
|
"type": "UnityEngine.Texture",
|
||||||
|
"defaultInstantiationMode": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"userAdded": false,
|
||||||
|
"type": "UnityEngine.Texture2D",
|
||||||
|
"defaultInstantiationMode": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"userAdded": false,
|
||||||
|
"type": "UnityEngine.Timeline.TimelineAsset",
|
||||||
|
"defaultInstantiationMode": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"defaultDependencyTypeInfo": {
|
||||||
|
"userAdded": false,
|
||||||
|
"type": "<default_scene_template_dependencies>",
|
||||||
|
"defaultInstantiationMode": 1
|
||||||
|
},
|
||||||
|
"newSceneOverride": 0
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue