Merge pull request 'feature/movement' (#2) from feature/movement into main

Reviewed-on: https://git.brew.monster/anhld/perfect-world-unity/pulls/2
This commit is contained in:
tungdv
2025-09-09 04:02:47 +00:00
65 changed files with 3993 additions and 332 deletions
+6
View File
@@ -0,0 +1,6 @@
{
"version": "1.0",
"components": [
"Microsoft.VisualStudio.Workload.ManagedGame"
]
}
+1
View File
@@ -1,4 +1,5 @@
{ {
"version": 1,
"name": "InputSystem_Actions", "name": "InputSystem_Actions",
"maps": [ "maps": [
{ {
Binary file not shown.
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: bcc16ddf2ea9dc340920ca8bcc54629c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+261
View File
@@ -0,0 +1,261 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!29 &1
OcclusionCullingSettings:
m_ObjectHideFlags: 0
serializedVersion: 2
m_OcclusionBakeSettings:
smallestOccluder: 5
smallestHole: 0.25
backfaceThreshold: 100
m_SceneGUID: 00000000000000000000000000000000
m_OcclusionCullingData: {fileID: 0}
--- !u!104 &2
RenderSettings:
m_ObjectHideFlags: 0
serializedVersion: 10
m_Fog: 0
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
m_FogMode: 3
m_FogDensity: 0.01
m_LinearFogStart: 0
m_LinearFogEnd: 300
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
m_AmbientIntensity: 1
m_AmbientMode: 0
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
m_HaloStrength: 0.5
m_FlareStrength: 1
m_FlareFadeSpeed: 3
m_HaloTexture: {fileID: 0}
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
m_DefaultReflectionMode: 0
m_DefaultReflectionResolution: 128
m_ReflectionBounces: 1
m_ReflectionIntensity: 1
m_CustomReflection: {fileID: 0}
m_Sun: {fileID: 0}
m_UseRadianceAmbientProbe: 0
--- !u!157 &3
LightmapSettings:
m_ObjectHideFlags: 0
serializedVersion: 13
m_BakeOnSceneLoad: 0
m_GISettings:
serializedVersion: 2
m_BounceScale: 1
m_IndirectOutputScale: 1
m_AlbedoBoost: 1
m_EnvironmentLightingMode: 0
m_EnableBakedLightmaps: 1
m_EnableRealtimeLightmaps: 0
m_LightmapEditorSettings:
serializedVersion: 12
m_Resolution: 2
m_BakeResolution: 40
m_AtlasSize: 1024
m_AO: 0
m_AOMaxDistance: 1
m_CompAOExponent: 1
m_CompAOExponentDirect: 0
m_ExtractAmbientOcclusion: 0
m_Padding: 2
m_LightmapParameters: {fileID: 0}
m_LightmapsBakeMode: 1
m_TextureCompression: 1
m_ReflectionCompression: 2
m_MixedBakeMode: 2
m_BakeBackend: 1
m_PVRSampling: 1
m_PVRDirectSampleCount: 32
m_PVRSampleCount: 512
m_PVRBounces: 2
m_PVREnvironmentSampleCount: 256
m_PVREnvironmentReferencePointCount: 2048
m_PVRFilteringMode: 1
m_PVRDenoiserTypeDirect: 1
m_PVRDenoiserTypeIndirect: 1
m_PVRDenoiserTypeAO: 1
m_PVRFilterTypeDirect: 0
m_PVRFilterTypeIndirect: 0
m_PVRFilterTypeAO: 0
m_PVREnvironmentMIS: 1
m_PVRCulling: 1
m_PVRFilteringGaussRadiusDirect: 1
m_PVRFilteringGaussRadiusIndirect: 1
m_PVRFilteringGaussRadiusAO: 1
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
m_PVRFilteringAtrousPositionSigmaIndirect: 2
m_PVRFilteringAtrousPositionSigmaAO: 1
m_ExportTrainingData: 0
m_TrainingDataDestination: TrainingData
m_LightProbeSampleCountMultiplier: 4
m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0}
m_LightingSettings: {fileID: 0}
--- !u!196 &4
NavMeshSettings:
serializedVersion: 2
m_ObjectHideFlags: 0
m_BuildSettings:
serializedVersion: 3
agentTypeID: 0
agentRadius: 0.5
agentHeight: 2
agentSlope: 45
agentClimb: 0.4
ledgeDropHeight: 0
maxJumpAcrossDistance: 0
minRegionArea: 2
manualCellSize: 0
cellSize: 0.16666667
manualTileSize: 0
tileSize: 256
buildHeightMesh: 0
maxJobWorkers: 0
preserveTilesOutsideBounds: 0
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
--- !u!1 &105404090
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 105404091}
- component: {fileID: 105404092}
m_Layer: 0
m_Name: Boostrap
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &105404091
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 105404090}
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!114 &105404092
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 105404090}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 2781611f0f83bf54290a9ec600543440, type: 3}
m_Name:
m_EditorClassIdentifier:
_nextSceneName: LoginScene
--- !u!1 &591506935
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 591506937}
- component: {fileID: 591506936}
m_Layer: 0
m_Name: GameSession
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &591506936
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 591506935}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: c9177aa9fcd28a94b9042f8a89fdac2d, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!4 &591506937
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 591506935}
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 &1654552490
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1654552492}
- component: {fileID: 1654552491}
m_Layer: 0
m_Name: AutoIniializer
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &1654552491
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1654552490}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: ddf01aaf66ec43f2bc9deda891a457d3, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!4 &1654552492
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1654552490}
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
SceneRoots:
m_ObjectHideFlags: 0
m_Roots:
- {fileID: 1654552492}
- {fileID: 591506937}
- {fileID: 105404091}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 40f9b53766c74f541b85df4d35cfc767
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 48fc9d6a0ce7ade4ba2075f927f8e305
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4bb534640fcb98b4cb869bdbb0059eb6
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;
namespace BrewMonster
{
public class BoostrapSceneController : MonoBehaviour
{
[SerializeField] private string _nextSceneName;
IEnumerator Start()
{
// Load the next scene after 1 second
yield return new WaitForSeconds(1f);
LoadNextScene();
}
private void LoadNextScene()
{
SceneManager.LoadScene(_nextSceneName);
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 2781611f0f83bf54290a9ec600543440
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 07afa074c434449b84fc580e4bd1b17e
timeCreated: 1757239245
@@ -0,0 +1,89 @@
using System;
using System.Reflection;
using UnityEngine;
namespace BrewMonster
{
public class AutoInitializer : MonoBehaviour
{
private void Awake()
{
Initialize();
}
private void Initialize()
{
var interfaceType = typeof(IAutoInitialize);
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
Type[] typesInAssembly;
try
{
typesInAssembly = assembly.GetTypes();
}
catch (ReflectionTypeLoadException e)
{
typesInAssembly = e.Types;
}
if (typesInAssembly == null)
{
continue;
}
foreach (var type in typesInAssembly)
{
if (type == null)
{
continue;
}
if (type.IsAbstract || type.IsInterface)
{
continue;
}
if (!interfaceType.IsAssignableFrom(type))
{
continue;
}
object instance = null;
try
{
if (typeof(ScriptableObject).IsAssignableFrom(type))
{
instance = ScriptableObject.CreateInstance(type);
}
else if (typeof(MonoBehaviour).IsAssignableFrom(type))
{
var go = new GameObject(type.Name);
go.transform.SetParent(transform, worldPositionStays: false);
instance = go.AddComponent(type);
}
else
{
instance = Activator.CreateInstance(type);
}
}
catch (Exception ex)
{
Debug.LogError($"AutoInitializer: Failed to create instance of {type.FullName}: {ex}");
continue;
}
try
{
(instance as IAutoInitialize)?.Initialize();
}
catch (Exception ex)
{
Debug.LogError($"AutoInitializer: Failed to initialize {type.FullName}: {ex}");
}
}
}
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ddf01aaf66ec43f2bc9deda891a457d3
timeCreated: 1757239452
@@ -0,0 +1,9 @@
using UnityEngine;
namespace BrewMonster
{
public class CoroutineRunner : MonoSingleton<CoroutineRunner>
{
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: c8a86796c56d63447aa1df962fb3abf6
@@ -0,0 +1,7 @@
namespace BrewMonster
{
public interface IAutoInitialize
{
void Initialize();
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 64cd9342d8974df18056b12aeb6f2651
timeCreated: 1757239258
@@ -0,0 +1,32 @@
#define ENALBE_LOGGING
using UnityEngine;
namespace BrewMonster
{
public class Logger
{
public static void Log(string message)
{
#if ENALBE_LOGGING
Debug.Log(message);
#endif
}
public static void LogError(string message)
{
#if ENALBE_LOGGING
Debug.LogError(message);
#endif
}
public static void LogWarning(string message)
{
#if ENALBE_LOGGING
Debug.LogWarning(message);
#endif
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 4e4b9f6cd855f4a4c9b02f681b12af2d
@@ -0,0 +1,38 @@
using UnityEngine;
namespace BrewMonster
{
public class MonoSingleton<T> : MonoBehaviour where T : MonoBehaviour
{
private static T _instance;
public static T Instance
{
get
{
if (_instance == null)
{
_instance = FindFirstObjectByType<T>();
if (_instance == null)
{
GameObject obj = new GameObject(typeof(T).Name);
_instance = obj.AddComponent<T>();
}
}
return _instance;
}
}
protected virtual void Awake()
{
_instance = this as T;
Initialize();
}
/// <summary>Override this method to initialize the singleton</summary>
protected virtual void Initialize()
{
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 139eb655406d7d447ba2d30309a84e00
@@ -1,4 +1,7 @@
using CSNetwork; using CSNetwork;
using CSNetwork.GPDataType;
using System;
using System.Runtime.InteropServices;
namespace PerfectWorld.Scripts.Managers namespace PerfectWorld.Scripts.Managers
{ {
@@ -6,12 +9,56 @@ namespace PerfectWorld.Scripts.Managers
{ {
public class EC_ManPlayer : IMsgHandler public class EC_ManPlayer : IMsgHandler
{ {
public int HandlerId => MANAGER_INDEX.MAN_PLAYER; public int HandlerId => (int)MANAGER_INDEX.MAN_PLAYER;
public bool ProcessMessage(ECMSG Msg) public bool ProcessMessage(ECMSG Msg)
{ {
if (Msg.iSubID == 0)
{
}
else if (Msg.iSubID < 0)
{
switch ((int)Msg.dwMsg)
{
case int value when value == EC_MsgDef.MSG_PM_PLAYERINFO:
{
OnMsgPlayerInfo(Msg);
break;
}
}
}
else
{
}
return true; return true;
} }
public void OnMsgPlayerInfo(ECMSG Msg)
{
int iHostID = (int)Msg.dwParam3;
int lenghtByte = Marshal.SizeOf<int>();
byte[] byteArray = new byte[lenghtByte];
byte[] data = (byte[])Msg.dwParam1;
for (int i = 0; i < lenghtByte; i++)
{
byteArray[i] = data[i];
}
int cid = BitConverter.ToInt32(byteArray);
switch (Convert.ToInt32(Msg.dwParam2))
{
case CommandID.PLAYER_INFO_1:
case CommandID.PLAYER_ENTER_WORLD:
case CommandID.PLAYER_ENTER_SLICE:
{
if (cid != iHostID)
{
GameController.Instance.Log("ElsePlayer has join");
}
break;
}
}
}
} }
} }
} }
@@ -1,3 +1,2 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: c6724bce59c34aa1bd3743616e212661 guid: be722834fd1fd9d49a39b91b5d19bfdb
timeCreated: 1757145906
@@ -13,7 +13,6 @@ namespace BrewMonster
EC_ManMessage.RegisterHandler(new EC_ManPlayer()); EC_ManMessage.RegisterHandler(new EC_ManPlayer());
} }
private void Update() private void Update()
{ {
EC_ManMessage.Tick(); EC_ManMessage.Tick();
@@ -0,0 +1,103 @@
using CSNetwork;
using CSNetwork.Protocols;
using System;
using BrewMonster;
using CSNetwork.Security;
using System.Threading.Tasks;
using System.Collections.Generic;
using CSNetwork.Protocols.RPCData;
namespace BrewMonster.Network
{
// How to connect to the server:
// 1. Set the connection info
// 2. Login
public class UnityGameSession : MonoSingleton<UnityGameSession>
{
private GameSession _gameSession;
private bool _isInitialized = false;
private string _ip = "";
private int _port = 0;
private string _username = "";
private string _password = "";
/// <summary>
/// Send a
/// </summary>
/// <param name="protocol"></param>
/// <param name="complete"></param>
public static void SendProtocol(Protocol protocol, Action complete = null)
{
if (!Instance._isInitialized)
{
return;
}
Instance._gameSession.SendProtocol(protocol, complete);
}
/// <summary>Set the connection info. This MUST be called call before login</summary>
public static void SetConnectionInfo(string ip, int port)
{
Logger.Log($"Set connection info {ip} {port}");
Instance._ip = ip;
Instance._port = port;
}
public static async Task Login(string username, string password, Action<bool> onLoginComplete = null)
{
Instance._username = username;
Instance._password = password;
if (Instance._ip == "" || Instance._port == 0)
{
Logger.LogError($"IP or port is not set {Instance._ip} {Instance._port}");
onLoginComplete?.Invoke(false);
return;
}
await Instance.ConnectAsync(Instance._ip, Instance._port);
if (!Instance._gameSession.IsConnected)
{
Logger.LogError($"Failed to connect to {Instance._ip} {Instance._port}");
onLoginComplete?.Invoke(false);
return;
}
Instance._gameSession.LoginAsync(username, password, onLoginComplete);
}
protected override void Initialize()
{
BaseSecurity.Initizalize();
ProtocolFactory.RegisterAllProtocols();
_gameSession = new GameSession();
_isInitialized = true;
DontDestroyOnLoad(gameObject);
}
/// <summary>Make sure username and password is set before calling this method</summary>
private async Task ConnectAsync(string ip, int port)
{
if (!Instance._isInitialized)
{
Logger.LogError("GameSession is not initialized");
return;
}
await Instance._gameSession.ConnectAsync(ip, port);
}
/// <summary>Get the list of created characters</summary>
public static void GetRoleListAsync(Action<List<RoleInfo>> callback = null)
{
Instance._gameSession.GetRoleListAsync(callback);
}
public static void SelectRoleAsync(RoleInfo roleInfo, Action<RoleInfo> callback = null)
{
Instance._gameSession.SelectRoleAsync(roleInfo, callback);
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: c9177aa9fcd28a94b9042f8a89fdac2d
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8511a50fc48e2cf4bbd9a6bf91442d50
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,16 @@
using UnityEngine;
public class EC_ElsePlayer : MonoBehaviour
{
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 0feb504dc7975e84dab03230dd3277a8
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7104ee5d1d322d64fb82447c7a9ab4c1
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5410bc4cbeb43b748a536a3de8683843
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,122 @@
using System.Collections.Generic;
using BrewMonster.Network;
using CSNetwork.Protocols;
using CSNetwork.Protocols.RPCData;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace BrewMonster.UI
{
/// <summary>
/// Login Flow:
/// 1. Enter username and password
/// 2. Click login button
/// 3. Login success, get the list of characters
/// 4. Open the select character screen
/// </summary>
public class LoginScreenUI : MonoBehaviour
{
[SerializeField] private TMP_InputField _usernameInputField;
[SerializeField] private TMP_InputField _passwordInputField;
[SerializeField] private Button _loginButton;
[SerializeField] private SelecScreenCharacter _selectCharacterScreen;
private List<RoleInfo> _roleInfos;
void Start()
{
_loginButton.onClick.AddListener(OnLoginButtonClicked);
}
// Update is called once per frame
void Update()
{
if (_roleInfos != null)
{
_selectCharacterScreen.InitScreen(_roleInfos, OnClickSelectCharacter);
_roleInfos = null;
}
}
public async void OnLoginButtonClicked()
{
Logger.Log("OnLoginButtonClicked");
string username = _usernameInputField.text;
string password = _passwordInputField.text;
UnityGameSession.SetConnectionInfo("103.182.22.52", 29000);
await UnityGameSession.Login(username, password, OnLoginComplete);
}
/// <summary>
/// Callback when the login is complete.
/// Then get the list of characters
/// </summary>
private void OnLoginComplete(bool result)
{
if (!result)
{
Logger.LogError("Login failed");
return;
}
UnityGameSession.GetRoleListAsync(OnGetRoleListComplete);
}
/// <summary>
/// Callback when the list of characters is retrieved.
/// Then move to the select character screen
/// </summary>
private void OnGetRoleListComplete(List<RoleInfo> roleInfos)
{
Logger.Log($"OnGetRoleListComplete {roleInfos.Count}");
_roleInfos = roleInfos;
}
private void OnClickSelectCharacter(RoleInfo roleInfo)
{
Logger.Log($"OnClickSelectCharacter {roleInfo.name}");
UnityGameSession.SelectRoleAsync(roleInfo, OnSelectRoleComplete);
}
private void OnSelectRoleComplete(RoleInfo roleInfo)
{
Logger.Log($"OnSelectRoleComplete {roleInfo.name} - {roleInfo.roleid}");
// now we have to enter the world
UnityGameSession.SendProtocol(
new enterworld()
{
Roleid = roleInfo.roleid,
Provider_link_id = 0,
L_timeout = 0,
Localsid = 0,
Locktime = 0,
Settime = 0,
Timeout = 0
}
);
}
#if UNITY_EDITOR
private void OnValidate()
{
if (_usernameInputField == null)
{
// find childrend with name "username"
_usernameInputField = transform.Find("username").GetComponent<TMP_InputField>();
}
if (_passwordInputField == null)
{
// find childrend with name "password"
_passwordInputField = transform.Find("password").GetComponent<TMP_InputField>();
}
if (_loginButton == null)
{
// find childrend with name "LoginBtn"
_loginButton = transform.Find("LoginBtn").GetComponent<Button>();
}
}
#endif
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 994f35e190b055c47903eb55ae125a9a
+44 -42
View File
@@ -11,9 +11,9 @@ GameObject:
- component: {fileID: 3412441340983701579} - component: {fileID: 3412441340983701579}
- component: {fileID: 4963688309523522575} - component: {fileID: 4963688309523522575}
- component: {fileID: 8371471143466595520} - component: {fileID: 8371471143466595520}
- component: {fileID: 8750866330409519469}
- component: {fileID: 2579337816850146009}
- component: {fileID: 7639115115142978997} - component: {fileID: 7639115115142978997}
- component: {fileID: 8960181021787475507}
- component: {fileID: 1591670752219322405}
m_Layer: 0 m_Layer: 0
m_Name: Character m_Name: Character
m_TagString: Untagged m_TagString: Untagged
@@ -90,8 +90,26 @@ MeshRenderer:
m_SortingLayer: 0 m_SortingLayer: 0
m_SortingOrder: 0 m_SortingOrder: 0
m_AdditionalVertexStreams: {fileID: 0} m_AdditionalVertexStreams: {fileID: 0}
--- !u!136 &8750866330409519469 --- !u!114 &7639115115142978997
CapsuleCollider: MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2013293210786114121}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: c0525de198450e14f9f6ad854b95ec99, type: 3}
m_Name:
m_EditorClassIdentifier:
txtName: {fileID: 0}
controller: {fileID: 8960181021787475507}
animator: {fileID: 1591670752219322405}
joystick: {fileID: 0}
btnJump: {fileID: 0}
btnRun: {fileID: 0}
--- !u!143 &8960181021787475507
CharacterController:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0} m_PrefabInstance: {fileID: 0}
@@ -105,54 +123,38 @@ CapsuleCollider:
serializedVersion: 2 serializedVersion: 2
m_Bits: 0 m_Bits: 0
m_LayerOverridePriority: 0 m_LayerOverridePriority: 0
m_IsTrigger: 0
m_ProvidesContacts: 0 m_ProvidesContacts: 0
m_Enabled: 1 m_Enabled: 1
serializedVersion: 2 serializedVersion: 3
m_Radius: 0.5
m_Height: 2 m_Height: 2
m_Direction: 1 m_Radius: 0.5
m_SlopeLimit: 45
m_StepOffset: 0.3
m_SkinWidth: 0.08
m_MinMoveDistance: 0.001
m_Center: {x: 0, y: 0, z: 0} m_Center: {x: 0, y: 0, z: 0}
--- !u!54 &2579337816850146009 --- !u!95 &1591670752219322405
Rigidbody: Animator:
m_ObjectHideFlags: 0 serializedVersion: 7
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2013293210786114121}
serializedVersion: 4
m_Mass: 1
m_Drag: 0
m_AngularDrag: 0.05
m_CenterOfMass: {x: 0, y: 0, z: 0}
m_InertiaTensor: {x: 1, y: 1, z: 1}
m_InertiaRotation: {x: 0, y: 0, z: 0, w: 1}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_ImplicitCom: 1
m_ImplicitTensor: 1
m_UseGravity: 1
m_IsKinematic: 0
m_Interpolate: 0
m_Constraints: 0
m_CollisionDetection: 0
--- !u!114 &7639115115142978997
MonoBehaviour:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0} m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2013293210786114121} m_GameObject: {fileID: 2013293210786114121}
m_Enabled: 1 m_Enabled: 1
m_EditorHideFlags: 0 m_Avatar: {fileID: 0}
m_Script: {fileID: 11500000, guid: dd1a1ec750c69604fafb72e91fd8e7b4, type: 3} m_Controller: {fileID: 0}
m_Name: m_CullingMode: 0
m_EditorClassIdentifier: m_UpdateMode: 0
txtName: {fileID: 2889286251427577339} m_ApplyRootMotion: 0
m_LinearVelocityBlending: 0
m_StabilizeFeet: 0
m_AnimatePhysics: 0
m_WarningMessage:
m_HasTransformHierarchy: 1
m_AllowConstantClipSamplingOptimization: 1
m_KeepAnimatorStateOnDisable: 0
m_WriteDefaultValuesOnDisable: 0
--- !u!1 &5363758751412688596 --- !u!1 &5363758751412688596
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
+116
View File
@@ -0,0 +1,116 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &5826062684364525110
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 78581589932911603}
m_Layer: 3
m_Name: Model
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &78581589932911603
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5826062684364525110}
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: 5695237227048099898}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &6513559496054861882
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 5695237227048099898}
- component: {fileID: 2967440448469171042}
- component: {fileID: 2038764726549499828}
m_Layer: 3
m_Name: HostPlayer
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &5695237227048099898
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6513559496054861882}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: -769.91, y: 45.8, z: -258.54}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 78581589932911603}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!143 &2967440448469171042
CharacterController:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6513559496054861882}
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_ProvidesContacts: 0
m_Enabled: 1
serializedVersion: 3
m_Height: 1.85
m_Radius: 0.35
m_SlopeLimit: 45
m_StepOffset: 0.3
m_SkinWidth: 0.02
m_MinMoveDistance: 0.001
m_Center: {x: 0, y: 0.9, z: 0}
--- !u!114 &2038764726549499828
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6513559496054861882}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: c0525de198450e14f9f6ad854b95ec99, type: 3}
m_Name:
m_EditorClassIdentifier:
txtName: {fileID: 0}
controller: {fileID: 2967440448469171042}
animator: {fileID: 0}
joystick: {fileID: 0}
btnJump: {fileID: 0}
btnRun: {fileID: 0}
extraGroundDistance: 0.05
radiusEpsilon: 0.005
groundMask:
serializedVersion: 2
m_Bits: 1
slopeToleranceDeg: 2
+7
View File
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 1f80fef119a826b4a826baf52a8f92d7
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+83
View File
@@ -2966,6 +2966,7 @@ GameObject:
m_Component: m_Component:
- component: {fileID: 1018020456} - component: {fileID: 1018020456}
- component: {fileID: 1018020457} - component: {fileID: 1018020457}
- component: {fileID: 1018020458}
m_Layer: 0 m_Layer: 0
m_Name: Game m_Name: Game
m_TagString: Untagged m_TagString: Untagged
@@ -2987,6 +2988,7 @@ Transform:
m_ConstrainProportionsScale: 0 m_ConstrainProportionsScale: 0
m_Children: m_Children:
- {fileID: 626090657} - {fileID: 626090657}
- {fileID: 2034856886}
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!114 &1018020457 --- !u!114 &1018020457
@@ -3003,6 +3005,18 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
characterPrefab: {fileID: 7639115115142978997, guid: 633f7b514d73bdb459636883927e2b1b, type: 3} characterPrefab: {fileID: 7639115115142978997, guid: 633f7b514d73bdb459636883927e2b1b, type: 3}
ground: {fileID: 626090657} ground: {fileID: 626090657}
--- !u!114 &1018020458
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1018020455}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 96073aa22df0eda49b4d56c0580aa806, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1 &1137567878 --- !u!1 &1137567878
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -3786,6 +3800,75 @@ RectTransform:
m_AnchoredPosition: {x: 0, y: 98} m_AnchoredPosition: {x: 0, y: 98}
m_SizeDelta: {x: 0, y: 100} m_SizeDelta: {x: 0, y: 100}
m_Pivot: {x: 0.5, y: 0.5} m_Pivot: {x: 0.5, y: 0.5}
--- !u!1001 &2034856885
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 1018020456}
m_Modifications:
- target: {fileID: 2013293210786114121, guid: 633f7b514d73bdb459636883927e2b1b, type: 3}
propertyPath: m_Name
value: Character
objectReference: {fileID: 0}
- target: {fileID: 2013293210786114121, guid: 633f7b514d73bdb459636883927e2b1b, type: 3}
propertyPath: m_IsActive
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3412441340983701579, guid: 633f7b514d73bdb459636883927e2b1b, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3412441340983701579, guid: 633f7b514d73bdb459636883927e2b1b, type: 3}
propertyPath: m_LocalPosition.y
value: 2.73
objectReference: {fileID: 0}
- target: {fileID: 3412441340983701579, guid: 633f7b514d73bdb459636883927e2b1b, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3412441340983701579, guid: 633f7b514d73bdb459636883927e2b1b, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 3412441340983701579, guid: 633f7b514d73bdb459636883927e2b1b, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3412441340983701579, guid: 633f7b514d73bdb459636883927e2b1b, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3412441340983701579, guid: 633f7b514d73bdb459636883927e2b1b, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3412441340983701579, guid: 633f7b514d73bdb459636883927e2b1b, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3412441340983701579, guid: 633f7b514d73bdb459636883927e2b1b, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3412441340983701579, guid: 633f7b514d73bdb459636883927e2b1b, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents:
- targetCorrespondingSourceObject: {fileID: 5363758751412688596, guid: 633f7b514d73bdb459636883927e2b1b, type: 3}
insertIndex: -1
addedObject: {fileID: 0}
m_SourcePrefab: {fileID: 100100000, guid: 633f7b514d73bdb459636883927e2b1b, type: 3}
--- !u!4 &2034856886 stripped
Transform:
m_CorrespondingSourceObject: {fileID: 3412441340983701579, guid: 633f7b514d73bdb459636883927e2b1b, type: 3}
m_PrefabInstance: {fileID: 2034856885}
m_PrefabAsset: {fileID: 0}
--- !u!1 &2082488502 --- !u!1 &2082488502
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
File diff suppressed because it is too large Load Diff
+1
View File
@@ -1,3 +1,4 @@
using BrewMonster.UI;
using CSNetwork.Protocols.RPCData; using CSNetwork.Protocols.RPCData;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
+136 -82
View File
@@ -1,11 +1,10 @@
using CSNetwork.Protocols.RPCData; using CSNetwork.Protocols;
using System.Data; using CSNetwork.Protocols.RPCData;
using System.Text; using System.Text;
using TMPro; using TMPro;
using UnityEngine; using UnityEngine;
using UnityEngine.InputSystem; using UnityEngine.InputSystem;
using UnityEngine.UI; using UnityEngine.UI;
using UnityEngine.Windows;
public class CharacterCtrl : MonoBehaviour public class CharacterCtrl : MonoBehaviour
{ {
@@ -17,6 +16,9 @@ public class CharacterCtrl : MonoBehaviour
[SerializeField] private Button btnJump; [SerializeField] private Button btnJump;
[SerializeField] private Button btnRun; [SerializeField] private Button btnRun;
PlayerStateMachine playerStateMachine;
PlayerMoveState moveState;
float playerSpeed = 5.0f; float playerSpeed = 5.0f;
float jumpHeight = 1.5f; float jumpHeight = 1.5f;
float gravityValue = -9.81f; float gravityValue = -9.81f;
@@ -24,10 +26,133 @@ public class CharacterCtrl : MonoBehaviour
Vector3 playerVelocity; Vector3 playerVelocity;
bool isGrounded = false; bool isGrounded = false;
bool isRun = false; bool isRun = false;
GameObject modle;
// ====== Ground cast config ======
[Header("Ground Cast")]
[Tooltip("Khoảng thêm ngoài skinWidth để SphereCast xuống (m ngắn)")]
[SerializeField] private float extraGroundDistance = 0.05f;
[Tooltip("Bớt bán kính một chút để tránh tự va vào capsule (epsilon)")]
[SerializeField] private float radiusEpsilon = 0.005f;
[Tooltip("Layer mặt đất")]
[SerializeField] private LayerMask groundMask;
[Tooltip("Layer mặt đất")]
[SerializeField] private float slopeToleranceDeg = 2f;
// cache tùy chọn (không bắt buộc)
float ccRadius, ccSkin;
RaycastHit lastGroundHit;
private void Awake()
{
moveState = new PlayerMoveState(this);
playerStateMachine = new PlayerStateMachine();
// Cache: không bắt buộc, nhưng gọn tay và ít gọi property lặp.
if (controller != null)
{
ccRadius = controller.radius;
ccSkin = controller.skinWidth;
}
SetModelHostPlayer();
}
public void SetModelHostPlayer()
{
//modle =
}
private void Start() private void Start()
{ {
//btnJump.onClick.AddListener(HandleJump); playerStateMachine.InitState(moveState);
// btnJump.onClick.AddListener(HandleJump);
}
private void Update()
{
// Nếu có thay đổi runtime, có thể lấy lại mỗi vài giây/Start nếu bạn thích:
// ccRadius = controller.radius; ccSkin = controller.skinWidth;
playerStateMachine.UpdateState();
}
public void HandleMovement()
{
// 1) Kiểm tra grounded bằng SphereCast ngắn dựa trên radius + skinWidth
isGrounded = GroundCheck(out lastGroundHit);
// 2) Input tạm thời: giữ nguyên như bạn
if (UnityEngine.Input.GetKeyDown(KeyCode.LeftShift)) SetStatusRun(true);
if (UnityEngine.Input.GetKeyUp(KeyCode.LeftShift)) SetStatusRun(false);
if (UnityEngine.Input.GetKeyDown(KeyCode.Space)) HandleJump();
// 3) Trọng lực / sticky
if (isGrounded && playerVelocity.y < 0f)
{
// Đè nhẹ để bám đất (tránh nhấp-nháy)
playerVelocity.y = -2f;
}
else
{
playerVelocity.y += gravityValue * Time.deltaTime;
}
// 4) Chuyển động phẳng
float x = joystick.Horizontal;
float z = joystick.Vertical;
Vector3 move = new Vector3(x, 0, z);
move = Vector3.ClampMagnitude(move, 1f);
if (move != Vector3.zero)
{
transform.forward = move;
if (isRun) SetAnimRun();
else SetAnimWalk();
}
else
{
SetAnimIdle();
}
Vector3 finalMove = (move * playerSpeed) + (playerVelocity.y * Vector3.up);
controller.Move(finalMove * Time.deltaTime);
}
private bool GroundCheck(out RaycastHit hit)
{
float radius = controller.radius;
float skin = controller.skinWidth;
float height = controller.height;
// Tâm capsule theo world
Vector3 cWorld = transform.TransformPoint(controller.center);
float hemi = Mathf.Max(0f, (height * 0.5f) - radius);
// Hai điểm top/bottom của capsule nhân vật (đang đứng)
Vector3 pTop = cWorld + Vector3.up * hemi;
Vector3 pBottom = cWorld - Vector3.up * hemi;
// Ta tạo một "đoạn capsule ngắn" gần đáy để sweep xuống
// Nhấc đoạn bắt đầu lên 1 chút để không bắt đầu trong trạng thái giao nhau
Vector3 startBottom = pBottom + Vector3.up * (skin + 0.01f);
Vector3 startTop = startBottom + Vector3.up * (radius * 2f - 0.02f); // chiều cao đoạn ngắn ~2*radius
float castRadius = Mathf.Max(0f, radius - radiusEpsilon);
float castDistance = skin + extraGroundDistance; // quãng sweep ngắn
bool hitSomething = Physics.CapsuleCast(
startTop, startBottom, castRadius,
Vector3.down, out hit, castDistance,
groundMask, QueryTriggerInteraction.Ignore
);
if (!hitSomething) return false;
// Lọc theo slope limit
float maxSlope = controller.slopeLimit + slopeToleranceDeg;
float slope = Vector3.Angle(hit.normal, Vector3.up);
if (slope > maxSlope) return false;
return true;
} }
private void HandleJump() private void HandleJump()
@@ -54,111 +179,40 @@ public class CharacterCtrl : MonoBehaviour
string roleName = "(Error decoding name)"; string roleName = "(Error decoding name)";
if (role.name != null && role.name.ByteArray != null) if (role.name != null && role.name.ByteArray != null)
{ {
// Be careful with encoding, assume UTF8 is correct roleName = Encoding.UTF8.GetString(role.name.ByteArray, 0, role.name.Length);
roleName = Encoding.UTF8.GetString(
role.name.ByteArray,
0,
role.name.Length
);
} }
Vector3 pos = new Vector3(role.posx, role.posy, role.posz); Vector3 pos = new Vector3(role.posx, role.posy, role.posz);
if(txtName != null) if (txtName != null) txtName.text = roleName;
{
txtName.text = roleName;
}
transform.position = pos; transform.position = pos;
Debug.LogError("Pos Character = " + pos); Debug.LogError("Pos Character = " + pos);
} }
private void Update()
{
isGrounded = controller.isGrounded;
if (UnityEngine.Input.GetKeyDown(KeyCode.LeftShift))
{
SetStatusRun(true);
}
if (UnityEngine.Input.GetKeyUp(KeyCode.LeftShift))
{
SetStatusRun(false);
}
if (UnityEngine.Input.GetKeyDown(KeyCode.Space))
{
HandleJump();
}
if (isGrounded && playerVelocity.y < 0)
{
playerVelocity.y = 0f;
}
float x = joystick.Horizontal;
float z = joystick.Vertical;
Vector3 move = new Vector3(x, 0, z);
move = Vector3.ClampMagnitude(move, 1f);
if (move != Vector3.zero)
{
transform.forward = move;
if (isRun)
{
SetAnimRun();
}
else
{
SetAnimWalk();
}
}
else
{
SetAnimIdle();
}
playerVelocity.y += gravityValue * Time.deltaTime;
Vector3 finalMove = (move * playerSpeed) + (playerVelocity.y * Vector3.up);
controller.Move(finalMove * Time.deltaTime);
}
private void SetAnimIdle() private void SetAnimIdle()
{ {
if(stateAnim == StateAnim.Idle || !isGrounded) if (stateAnim == StateAnim.Idle || !isGrounded) return;
{
return;
}
stateAnim = StateAnim.Idle; stateAnim = StateAnim.Idle;
animator.SetTrigger("Idle"); animator.SetTrigger("Idle");
} }
private void SetAnimRun() private void SetAnimRun()
{ {
if (stateAnim == StateAnim.Run || !isGrounded) if (stateAnim == StateAnim.Run || !isGrounded) return;
{
return;
}
stateAnim = StateAnim.Run; stateAnim = StateAnim.Run;
animator.SetTrigger("Run"); animator.SetTrigger("Run");
} }
private void SetAnimWalk() private void SetAnimWalk()
{ {
if (stateAnim == StateAnim.Walk || !isGrounded) if (stateAnim == StateAnim.Walk || !isGrounded) return;
{
return;
}
stateAnim = StateAnim.Walk; stateAnim = StateAnim.Walk;
animator.SetTrigger("Walk"); animator.SetTrigger("Walk");
} }
private void SetAnimJump() private void SetAnimJump()
{ {
if (stateAnim == StateAnim.Jump) if (stateAnim == StateAnim.Jump) return;
{
return;
}
stateAnim = StateAnim.Jump; stateAnim = StateAnim.Jump;
// Tạm dùng Idle trigger như code cũ của bạn
animator.SetTrigger("Idle"); animator.SetTrigger("Idle");
} }
} }
+11
View File
@@ -0,0 +1,11 @@
using UnityEngine;
struct cmd_player_move
{
Vector3 vCurPos;
Vector3 vNextPos;
ushort use_time;
short sSpeed; // Move speed 8.8 fix-point
byte move_mode; // Walk run swim fly .... walk_back run_back
ushort stamp; // move command stamp
};
+2
View File
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: f59c799d38bfd9a4faa671a30dec48ae
+29
View File
@@ -1,18 +1,47 @@
using CSNetwork.Protocols.RPCData; using CSNetwork.Protocols.RPCData;
using System.Data; using System.Data;
using Unity.VisualScripting;
using UnityEngine; using UnityEngine;
public class GameController : MonoBehaviour public class GameController : MonoBehaviour
{ {
private static GameController instance;
[SerializeField] private CharacterCtrl characterPrefab; [SerializeField] private CharacterCtrl characterPrefab;
[SerializeField] private Transform ground; [SerializeField] private Transform ground;
Camera camera; Camera camera;
public static GameController Instance
{
get
{
if (instance == null)
{
instance = new GameController();
}
return instance;
}
}
private void Awake()
{
if(instance == null)
{
instance = this;
}
}
private void Start() private void Start()
{ {
camera = Camera.main; camera = Camera.main;
} }
public void Log(string s)
{
Debug.LogError(s);
}
public void InitCharacter(RoleInfo roleInfo) public void InitCharacter(RoleInfo roleInfo)
{ {
CharacterCtrl character = Instantiate(characterPrefab, transform); CharacterCtrl character = Instantiate(characterPrefab, transform);
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 975de416ff502c34cac627a81815e2b0
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+25
View File
@@ -0,0 +1,25 @@
public static class AAssist
{
// Bản generic (giống template C++)
public static void a_ClampRoof<T>(ref T x, T max) where T : System.IComparable<T>
{
if (x.CompareTo(max) > 0) x = max;
}
// Tiện dụng cho float (Unity)
public static void a_ClampRoof(ref float x, float max)
{
if (x > max) x = max;
}
// (Tuỳ chọn) giữ luôn 2 hàm “họ hàng” như trong header gốc:
public static void a_ClampFloor<T>(ref T x, T min) where T : System.IComparable<T>
{
if (x.CompareTo(min) < 0) x = min;
}
public static void a_Clamp<T>(ref T x, T min, T max) where T : System.IComparable<T>
{
if (x.CompareTo(min) < 0) x = min;
if (x.CompareTo(max) > 0) x = max;
}
}
+2
View File
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 43ba3172dd47c0a44b7194919c6104c4
+44
View File
@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Runtime.ConstrainedExecution;
using System.Text;
using UnityEngine;
public class CECHostMove
{
// Giữ reference tới CECHostPlayer y như bản gốc
}
public struct CDR_INFO
{
//the aabb
public Vector3 vCenter;
//@note : the caller should make sure ext(.x, .y, .z) > 0. By Kuiwu[22/9/2005]
public Vector3 vExtent;
public float fStepHeight;
// Velocity Info
public Vector3 vXOZVelDir;
public float fYVel;
public float fSpeed;
// time span ( sec )
public float t;
// Gravity acceleration
public float fGravityAccel;
// the Climb Slope Thresh
public float fSlopeThresh;
// Tangent plane Info
public Vector3 vTPNormal;
// Absolute Velocity: output for forcast!
public Vector3 vAbsVelocity;
//the moving dist
public float fMoveDist;
};
+2
View File
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: cd5fc9aa768e77b4f90b7b8a4c5514c2
+239
View File
@@ -0,0 +1,239 @@
using System;
using TMPro;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.LightTransport;
public static class EC_CDR
{
// Cho phép CECHostMove gán mask theo scene (giữ linh hoạt nhưng không phá cấu trúc)
public static LayerMask BrushMask { get; set; } = ~0;
public static LayerMask TerrainMask { get; set; } = ~0;
static LayerMask UsedMask_Ground() => BrushMask | TerrainMask;
// == Thay CollideWithEnv (C++) bằng BoxCast ==
static bool CollideWithEnv_BoxCast(Vector3 vStart, Vector3 vDelta, Vector3 vExt,
LayerMask mask,
out RaycastHit hit, out float fFraction, out Vector3 vHitNormal, out bool bStartSolid,
float skin = 0.01f)
{
hit = default;
vHitNormal = Vector3.up;
bStartSolid = false;
fFraction = 1.0f;
float dist = vDelta.magnitude;
if (dist <= 1e-6f) return false;
// start-in-solid
var overlapped = Physics.OverlapBox(vStart, vExt - Vector3.one * skin, Quaternion.identity, mask, QueryTriggerInteraction.Ignore);
if (overlapped != null && overlapped.Length > 0)
{
bStartSolid = true;
return true;
}
// sweep AABB
Vector3 dir = vDelta / Mathf.Max(dist, 1e-6f);
if (Physics.BoxCast(vStart, vExt - Vector3.one * skin, dir, out hit, Quaternion.identity, dist, mask, QueryTriggerInteraction.Ignore))
{
fFraction = Mathf.Clamp01(hit.distance / Mathf.Max(dist, 1e-6f));
vHitNormal = hit.normal;
return true;
}
return false;
}
// == Thay RetrieveSupportPlane (C++) bằng Raycast xuống ==
static bool DoGroundProbe(Vector3 vStart, Vector3 vExt, float fDeltaY, LayerMask mask,
out Vector3 vEnd, out Vector3 vHitNormal, out bool bSupport,
float skin = 0.01f)
{
vEnd = vStart;
vHitNormal = Vector3.up;
bSupport = false;
float dist = Mathf.Max(fDeltaY, 0f) + vExt.y + skin + 0.05f;
Vector3 origin = vStart + Vector3.up * 0.05f;
if (Physics.Raycast(origin, Vector3.down, out RaycastHit hit, dist, mask, QueryTriggerInteraction.Ignore))
{
vHitNormal = hit.normal;
vEnd = new Vector3(vStart.x, hit.point.y + vExt.y + skin, vStart.z);
bSupport = (vHitNormal.y >= 0f);
return true;
}
return true; // không thấy ground → bSupport=false
}
// ======= STATIC OnGroundMove GIỮ NGUYÊN VAI TRÒ TOÀN CỤC (C API) =======
public static void OnGroundMove(ref CDR_INFO CDRInfo)
{
const float VEL_EPSILON = 1e-4f;
const float DIST_EPSILON = 1e-4f;
const float NORMAL_EPSILON = 1e-2f;
const float VEL_MAX_SPEED = 200f;
const float VEL_REFLECT = 0.3f;
CDRInfo.fMoveDist = 0.0f;
bool bFreeFall = (CDRInfo.vTPNormal.y < CDRInfo.fSlopeThresh);
if (Mathf.Abs(CDRInfo.fYVel) < VEL_EPSILON && Mathf.Abs(CDRInfo.fSpeed) < VEL_EPSILON && !bFreeFall)
return;
float fYVel = CDRInfo.fYVel;
bool bJump = (fYVel > 0.5f);
Vector3 vVelocity = CDRInfo.fSpeed * new Vector3(CDRInfo.vXOZVelDir.x, 0f, CDRInfo.vXOZVelDir.z) + fYVel * Vector3.up;
if (bFreeFall)
{
vVelocity += -CDRInfo.fGravityAccel * CDRInfo.t * Vector3.up;
fYVel += -CDRInfo.fGravityAccel * CDRInfo.t;
}
Vector3 vVelDir = vVelocity;
float fVelSpeed = vVelDir.magnitude;
if (fVelSpeed > 1e-6f) vVelDir /= fVelSpeed; else vVelDir = Vector3.zero;
if (!bFreeFall) fVelSpeed = Mathf.Min(fVelSpeed, VEL_MAX_SPEED);
vVelocity = vVelDir * fVelSpeed;
float dtp = Vector3.Dot(vVelDir, CDRInfo.vTPNormal);
if (dtp < 0f || !bJump)
{
vVelocity = (vVelDir - CDRInfo.vTPNormal * dtp - CDRInfo.vTPNormal * dtp * 0.01f) * fVelSpeed;
}
CDRInfo.vAbsVelocity = vVelocity;
Vector3 vStart = CDRInfo.vCenter;
Vector3 vExt = CDRInfo.vExtent;
float fTime = CDRInfo.t;
Vector3 vDelta, vNormal = Vector3.up, vFinalPos = vStart;
bool bPull = false;
bool bTryPull = false;
int nTry = 0;
LayerMask mask = UsedMask_Ground();
while (nTry < 4)
{
vDelta = vVelocity * fTime;
float fDeltaDist = vDelta.magnitude;
if (fDeltaDist < DIST_EPSILON) break;
bool hasHit = CollideWithEnv_BoxCast(vStart, vDelta, vExt, mask,
out RaycastHit hit, out float fFraction, out Vector3 hitNormal, out bool bStartSolid);
nTry++;
if (bStartSolid)
{
CDRInfo.fMoveDist = 0f;
if (CDRInfo.vTPNormal.y < CDRInfo.fSlopeThresh) CDRInfo.vTPNormal = Vector3.up;
return;
}
if (!hasHit)
{
vFinalPos = vStart + vDelta;
CDRInfo.fMoveDist += fDeltaDist;
break;
}
vStart += vDelta * fFraction;
CDRInfo.fMoveDist += (fDeltaDist * fFraction);
fTime -= fTime * fFraction;
vNormal = hitNormal;
// Step-up (giữ tinh thần bản gốc)
if (!bFreeFall && !bTryPull && !bJump)
{
float skin = 0.01f;
Vector3 vStartUp = vStart + new Vector3(0f, CDRInfo.fStepHeight, 0f);
bool upBlocked = Physics.CheckBox(vStartUp, vExt - Vector3.one * skin, Quaternion.identity, mask, QueryTriggerInteraction.Ignore);
if (!upBlocked)
{
Vector3 vDelta2 = vVelocity;
bool hasHit2 = CollideWithEnv_BoxCast(vStartUp, vDelta2, vExt, mask,
out RaycastHit hit2, out float frac2, out Vector3 hitNormal2, out bool bStartSolid2);
if (hasHit2) vDelta2 *= frac2;
if (vDelta2.sqrMagnitude >= (vExt.x * vExt.x * 4f))
{
vStart = vStartUp;
vDelta = vDelta2;
float distAll = vVelocity.magnitude;
float distMoved = vDelta.magnitude;
if (distAll > 1e-6f) fTime *= Mathf.Clamp01(distMoved / Mathf.Max(distAll, 1e-6f));
bPull = true;
}
}
bTryPull = true;
}
if (!bPull)
{
if (vVelocity.sqrMagnitude > 1e-12f)
{
vVelDir = vVelocity.normalized;
fVelSpeed = vVelocity.magnitude * (1f - nTry * 0.1f);
dtp = Vector3.Dot(vNormal, vVelDir);
float fRelSpeed = Mathf.Min(fVelSpeed, 5.0f);
if (dtp >= 0f && dtp < 1e-4f)
{
vVelocity += vNormal * VEL_REFLECT * fRelSpeed;
}
else
{
vVelocity = (vVelDir - vNormal * dtp) * fVelSpeed - vNormal * dtp * VEL_REFLECT * fRelSpeed;
}
}
if (fYVel > VEL_EPSILON)
{
if (vNormal.y >= CDRInfo.fSlopeThresh || vNormal.y < -NORMAL_EPSILON) fYVel = 0f;
}
else if (fYVel < -VEL_EPSILON)
{
if (vNormal.y >= CDRInfo.fSlopeThresh) fYVel = 0f;
}
}
}
// “vertical ground trace” thay RetrieveSupportPlane
Vector3 vTPNormal = Vector3.zero;
Vector3 vFinal = vFinalPos;
float downDist = 0.3f;
if (bPull) downDist = CDRInfo.fStepHeight + 0.1f;
if (bJump) downDist = 0.0f;
if (downDist > 0f)
{
if (!DoGroundProbe(vFinalPos, vExt, downDist, mask, out Vector3 vEnd, out Vector3 groundNormal, out bool bSupport))
{
CDRInfo.fMoveDist = 0f;
CDRInfo.vTPNormal = Vector3.up;
return;
}
if (bSupport)
{
vFinal = vEnd;
if (!bJump) vTPNormal = groundNormal;
}
}
if ((vTPNormal.y >= CDRInfo.fSlopeThresh && fYVel < 0.0f) || (!bJump && fYVel > 0.0f))
fYVel = 0.0f;
CDRInfo.vCenter = vFinal;
CDRInfo.fYVel = fYVel;
if (vTPNormal != Vector3.zero) CDRInfo.vTPNormal = vTPNormal;
}
}
+2
View File
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 83067442406d6e5459471cca0b1ff2d3
+6
View File
@@ -0,0 +1,6 @@
using UnityEngine;
public class EC_Player
{
public Bounds m_aabbServer;
}
+2
View File
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: be4a22babee7846459b0421234a44c99
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9ef8d28320e272c47b341e1a2aca2ff5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
using UnityEngine;
public class PlayerMoveState : PlayerState
{
public PlayerMoveState(CharacterCtrl characterCtrl) : base(characterCtrl)
{
}
public override void Enter()
{
}
public override void Exit()
{
}
public override void Update()
{
_characterCtrl.HandleMovement();
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 979df0dcb6a16cf47a77106a9c9ebb8f
+13
View File
@@ -0,0 +1,13 @@
using UnityEngine;
public abstract class PlayerState
{
protected readonly CharacterCtrl _characterCtrl;
public PlayerState(CharacterCtrl characterCtrl)
{
_characterCtrl = characterCtrl;
}
public abstract void Enter();
public abstract void Exit();
public abstract void Update();
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 1c3e8f4466ed88340aeb27f86dc0c172
+39
View File
@@ -0,0 +1,39 @@
using UnityEngine;
public class PlayerStateMachine
{
PlayerState _state;
CharacterCtrl _characterCtrl;
public void InitState(PlayerState state)
{
if (_state != null)
{
Debug.LogWarning("_state is already inited");
return;
}
_state = state;
}
public void ChangeState(PlayerState state)
{
if (_state == null )
{
Debug.LogError("you need to init state first ");
return;
}
if (_state == state)
{
Debug.LogWarning("Unchanged state");
}
_state.Exit();
_state = state;
_state.Enter();
}
public void UpdateState()
{
_state.Update();
}
//TODO: tìm OnMsgHstCorrectPos bên C++
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 99f098b6660da2c4f8ff06b5043a254b
+9 -3
View File
@@ -2,18 +2,24 @@ using CSNetwork.Protocols.RPCData;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
using BrewMonster;
public class SelecScreenCharacter : MonoBehaviour namespace BrewMonster.UI
{ {
[SerializeField] private CharacterItemUI characterItemPrefab; public class SelecScreenCharacter : MonoBehaviour
{
[SerializeField] private GameObject characterItemPrefab;
[SerializeField] private RectTransform parentItems; [SerializeField] private RectTransform parentItems;
public void InitScreen(List<RoleInfo> roleInfos, Action<RoleInfo> OnClickItemChar) public void InitScreen(List<RoleInfo> roleInfos, Action<RoleInfo> OnClickItemChar)
{ {
Logger.Log($"InitScreen {roleInfos.Count}");
foreach(RoleInfo info in roleInfos) foreach(RoleInfo info in roleInfos)
{ {
CharacterItemUI item = Instantiate(characterItemPrefab, parentItems); Logger.Log($"Role Name {info.roleid}");
CharacterItemUI item = Instantiate(characterItemPrefab, parentItems).GetComponent<CharacterItemUI>();
item.InitItem(info, OnClickItemChar); item.InitItem(info, OnClickItemChar);
} }
} }
} }
}
+1
View File
@@ -1,5 +1,6 @@
{ {
"dependencies": { "dependencies": {
"com.boxqkrtm.ide.cursor": "https://github.com/boxqkrtm/com.unity.ide.cursor.git",
"com.unity.ai.navigation": "2.0.8", "com.unity.ai.navigation": "2.0.8",
"com.unity.collab-proxy": "2.9.1", "com.unity.collab-proxy": "2.9.1",
"com.unity.ide.rider": "3.0.36", "com.unity.ide.rider": "3.0.36",
+9
View File
@@ -1,5 +1,14 @@
{ {
"dependencies": { "dependencies": {
"com.boxqkrtm.ide.cursor": {
"version": "https://github.com/boxqkrtm/com.unity.ide.cursor.git",
"depth": 0,
"source": "git",
"dependencies": {
"com.unity.test-framework": "1.1.9"
},
"hash": "38fecf55e4fd94ccfe58a92ed8ad1a529ba1694e"
},
"com.unity.ai.navigation": { "com.unity.ai.navigation": {
"version": "2.0.8", "version": "2.0.8",
"depth": 0, "depth": 0,
+1 -1
View File
@@ -25,7 +25,7 @@ EditorSettings:
m_AsyncShaderCompilation: 1 m_AsyncShaderCompilation: 1
m_PrefabModeAllowAutoSave: 1 m_PrefabModeAllowAutoSave: 1
m_EnterPlayModeOptionsEnabled: 1 m_EnterPlayModeOptionsEnabled: 1
m_EnterPlayModeOptions: 0 m_EnterPlayModeOptions: 3
m_GameObjectNamingDigits: 1 m_GameObjectNamingDigits: 1
m_GameObjectNamingScheme: 0 m_GameObjectNamingScheme: 0
m_AssetNamingUsesSpace: 1 m_AssetNamingUsesSpace: 1
+2 -26
View File
@@ -2,13 +2,13 @@
%TAG !u! tag:unity3d.com,2011: %TAG !u! tag:unity3d.com,2011:
--- !u!78 &1 --- !u!78 &1
TagManager: TagManager:
serializedVersion: 2 serializedVersion: 3
tags: [] tags: []
layers: layers:
- Default - Default
- TransparentFX - TransparentFX
- Ignore Raycast - Ignore Raycast
- - Player
- Water - Water
- UI - UI
- -
@@ -50,27 +50,3 @@ TagManager:
- Light Layer 5 - Light Layer 5
- Light Layer 6 - Light Layer 6
- Light Layer 7 - Light Layer 7
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-