Squashed commit of the following:

commit 428243f4a6
Author: AsanoRema <asanorema2036@gmail.com>
Date:   Sat Aug 29 13:43:13 2026 +0300

    Squashed commit of the following:

    commit 68e78fa464
    Author: AsanoRema <asanorema2036@gmail.com>
    Date:   Sat Aug 29 13:41:49 2026 +0300

        Updated .gitignore

commit 9f87122a34
Author: AsanoRema <asanorema2036@gmail.com>
Date:   Sat Aug 29 13:34:57 2026 +0300

    Added Dohya

commit f6a7547e84
Author: AsanoRema <asanorema2036@gmail.com>
Date:   Fri Aug 21 17:59:13 2026 +0300

    Fixed

commit b98901c366
Author: AsanoRema <asanorema2036@gmail.com>
Date:   Tue Aug 18 17:37:22 2026 +0300

    Added new particle Package

commit bb2f4a3b16
Author: AsanoRema <asanorema2036@gmail.com>
Date:   Tue Aug 18 17:17:48 2026 +0300

    Map mehanic ready to multiplayer

commit c01ff800f6
Author: AsanoRema <asanorema2036@gmail.com>
Date:   Tue Aug 18 16:16:19 2026 +0300

    Squashed commit of the following:

    commit 173bbb165c
    Author: henjkey <henjkey@gmail.com>
    Date:   Fri Aug 14 18:51:23 2026 +0500

        Mappp

    commit d559ab338a
    Author: henjkey <henjkey@gmail.com>
    Date:   Thu Aug 13 18:42:41 2026 +0500

        Map

        Controller
        Coordinates
        Target System
        Crosshair System
        Radar System
This commit is contained in:
2026-08-29 13:45:55 +03:00
parent 68e78fa464
commit ffa1064063
3344 changed files with 4722286 additions and 105458 deletions
@@ -0,0 +1,458 @@
using TMPro;
using Unity.Netcode;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
public static class CannonPrototypeSetup
{
private const string DataFolder = "Assets/CONTENT/Game/Data/Cannon";
private const string CannonConfigPath = DataFolder + "/CannonConfig.asset";
private const string CannonShockwavePath = DataFolder + "/CannonShockwave.asset";
private const string RocketShockwavePath = DataFolder + "/RocketImpactShockwave.asset";
private const string PlayerPrefabPath =
"Assets/CONTENT/Friendslop/Prefabs/NetworkPlayer.prefab";
private const string RocketPrefabPath =
"Assets/CONTENT/Game/Prefabs/Items/Ready-Rocket-Standart.prefab";
private const string StandardRocketDefinitionPath =
"Assets/CONTENT/Game/Data/Items/Rocket-Ready/Ready-Rocket-Standart.asset";
private const string LeverPrefabPath =
"Assets/CONTENT/Game/Prefabs/Interaction/PhysicalLever.prefab";
[MenuItem("FORT-BO/Cannon/Configure Network Prototype")]
public static void ConfigureNetworkPrototype()
{
if (Application.isPlaying)
{
Debug.LogWarning("Stop Play Mode before configuring the cannon prototype.");
return;
}
EnsureDataFolder();
CannonConfig config = GetOrCreateCannonConfig();
ShockwaveProfile cannonShockwave = GetOrCreateProfile(
CannonShockwavePath,
new ShockwaveZone
{
Radius = 8f,
PlayerImpulse = 12f,
RigidbodyImpulse = 18f,
UpwardBias = 0.35f,
CameraShakeAmplitude = 0.22f,
CameraShakeDuration = 0.9f,
CameraShakeFrequency = 28f
},
new ShockwaveZone
{
Radius = 18f,
PlayerImpulse = 5f,
RigidbodyImpulse = 8f,
UpwardBias = 0.25f,
CameraShakeAmplitude = 0.12f,
CameraShakeDuration = 0.75f,
CameraShakeFrequency = 24f
},
new ShockwaveZone
{
Radius = 35f,
PlayerImpulse = 0f,
RigidbodyImpulse = 1.5f,
UpwardBias = 0.1f,
CameraShakeAmplitude = 0.055f,
CameraShakeDuration = 0.55f,
CameraShakeFrequency = 20f
});
ShockwaveProfile rocketShockwave = GetOrCreateProfile(
RocketShockwavePath,
new ShockwaveZone
{
Radius = 4f,
PlayerImpulse = 8f,
RigidbodyImpulse = 12f,
UpwardBias = 0.4f,
CameraShakeAmplitude = 0.18f,
CameraShakeDuration = 0.7f,
CameraShakeFrequency = 27f
},
new ShockwaveZone
{
Radius = 8f,
PlayerImpulse = 3f,
RigidbodyImpulse = 5f,
UpwardBias = 0.3f,
CameraShakeAmplitude = 0.09f,
CameraShakeDuration = 0.55f,
CameraShakeFrequency = 23f
},
new ShockwaveZone
{
Radius = 14f,
PlayerImpulse = 0f,
RigidbodyImpulse = 0.5f,
UpwardBias = 0.1f,
CameraShakeAmplitude = 0.04f,
CameraShakeDuration = 0.4f,
CameraShakeFrequency = 18f
});
ConfigurePlayerPrefab();
ConfigureRocketPrefab(rocketShockwave);
ConfigureStandardRocketDefinition();
NetworkCannonController cannon = ConfigureCannonScene(config, cannonShockwave);
ConfigureMapMarker();
AssetDatabase.SaveAssets();
EditorSceneManager.MarkSceneDirty(cannon.gameObject.scene);
EditorSceneManager.SaveOpenScenes();
Selection.activeObject = cannon.gameObject;
Debug.Log(
"[Cannon] Network prototype configured. Insert a ready rocket, " +
"set delay with -/+ buttons and pull the fire lever.", cannon);
}
private static CannonConfig GetOrCreateCannonConfig()
{
CannonConfig config = AssetDatabase.LoadAssetAtPath<CannonConfig>(CannonConfigPath);
if (config == null)
{
config = ScriptableObject.CreateInstance<CannonConfig>();
AssetDatabase.CreateAsset(config, CannonConfigPath);
}
SerializedObject serialized = new(config);
SetFloat(serialized, "minimumDelay", 0f);
SetFloat(serialized, "maximumDelay", 30f);
SetFloat(serialized, "defaultDelay", 5f);
SetFloat(serialized, "adjustmentStep", 1f);
serialized.ApplyModifiedPropertiesWithoutUndo();
EditorUtility.SetDirty(config);
return config;
}
private static ShockwaveProfile GetOrCreateProfile(
string path,
params ShockwaveZone[] zones)
{
ShockwaveProfile profile = AssetDatabase.LoadAssetAtPath<ShockwaveProfile>(path);
if (profile == null)
{
profile = ScriptableObject.CreateInstance<ShockwaveProfile>();
AssetDatabase.CreateAsset(profile, path);
}
SerializedObject serialized = new(profile);
SerializedProperty array = serialized.FindProperty("zones");
array.arraySize = zones.Length;
for (int index = 0; index < zones.Length; index++)
{
SerializedProperty element = array.GetArrayElementAtIndex(index);
ShockwaveZone zone = zones[index];
element.FindPropertyRelative("Radius").floatValue = zone.Radius;
element.FindPropertyRelative("PlayerImpulse").floatValue = zone.PlayerImpulse;
element.FindPropertyRelative("RigidbodyImpulse").floatValue = zone.RigidbodyImpulse;
element.FindPropertyRelative("UpwardBias").floatValue = zone.UpwardBias;
element.FindPropertyRelative("CameraShakeAmplitude").floatValue =
zone.CameraShakeAmplitude;
element.FindPropertyRelative("CameraShakeDuration").floatValue =
zone.CameraShakeDuration;
element.FindPropertyRelative("CameraShakeFrequency").floatValue =
zone.CameraShakeFrequency;
}
serialized.ApplyModifiedPropertiesWithoutUndo();
EditorUtility.SetDirty(profile);
return profile;
}
private static void ConfigurePlayerPrefab()
{
GameObject root = PrefabUtility.LoadPrefabContents(PlayerPrefabPath);
try
{
GetOrAdd<PlayerCameraShakeController>(root);
GetOrAdd<PlayerImpactController>(root);
PrefabUtility.SaveAsPrefabAsset(root, PlayerPrefabPath);
}
finally
{
PrefabUtility.UnloadPrefabContents(root);
}
}
private static void ConfigureRocketPrefab(ShockwaveProfile rocketShockwave)
{
GameObject root = PrefabUtility.LoadPrefabContents(RocketPrefabPath);
try
{
NetworkRocketItem rocket = root.GetComponent<NetworkRocketItem>();
NetworkShockwaveEmitter emitter = GetOrAdd<NetworkShockwaveEmitter>(root);
RocketImpactExplosion explosion = GetOrAdd<RocketImpactExplosion>(root);
SerializedObject serializedEmitter = new(emitter);
SetObject(serializedEmitter, "profile", rocketShockwave);
SetObject(serializedEmitter, "origin", root.transform);
serializedEmitter.ApplyModifiedPropertiesWithoutUndo();
SerializedObject serializedExplosion = new(explosion);
SetObject(serializedExplosion, "rocket", rocket);
SetObject(serializedExplosion, "shockwave", emitter);
serializedExplosion.ApplyModifiedPropertiesWithoutUndo();
PrefabUtility.SaveAsPrefabAsset(root, RocketPrefabPath);
}
finally
{
PrefabUtility.UnloadPrefabContents(root);
}
}
private static void ConfigureStandardRocketDefinition()
{
RocketItemDefinition definition =
AssetDatabase.LoadAssetAtPath<RocketItemDefinition>(StandardRocketDefinitionPath);
if (definition == null)
return;
SerializedObject serialized = new(definition);
serialized.FindProperty("missileType").enumValueIndex = (int)MissileType.Standard;
serialized.ApplyModifiedPropertiesWithoutUndo();
EditorUtility.SetDirty(definition);
}
private static NetworkCannonController ConfigureCannonScene(
CannonConfig config,
ShockwaveProfile cannonShockwave)
{
GameObject root = GameObject.Find("Cannon Prototype");
bool created = root == null;
if (created)
{
root = new GameObject("Cannon Prototype");
root.transform.SetPositionAndRotation(
new Vector3(132f, 2.55f, 24.3f),
Quaternion.Euler(0f, 90f, 0f));
Undo.RegisterCreatedObjectUndo(root, "Create cannon prototype");
}
GetOrAdd<NetworkObject>(root);
NetworkCannonController controller = GetOrAdd<NetworkCannonController>(root);
NetworkShockwaveEmitter emitter = GetOrAdd<NetworkShockwaveEmitter>(root);
CannonControlBinder binder = GetOrAdd<CannonControlBinder>(root);
CannonView view = GetOrAdd<CannonView>(root);
Transform baseVisual = GetOrCreatePrimitive(
root.transform, "Cannon Base", PrimitiveType.Cube);
baseVisual.localPosition = new Vector3(0f, 0.75f, 0f);
baseVisual.localRotation = Quaternion.identity;
baseVisual.localScale = new Vector3(2.2f, 1.5f, 2.2f);
Transform recoil = GetOrCreateChild(root.transform, "Barrel Recoil");
recoil.localPosition = new Vector3(0f, 2.1f, 0f);
recoil.localRotation = Quaternion.identity;
recoil.localScale = Vector3.one;
Transform barrel = GetOrCreatePrimitive(recoil, "Barrel", PrimitiveType.Cube);
barrel.localPosition = new Vector3(0f, 0f, 2.1f);
barrel.localRotation = Quaternion.identity;
barrel.localScale = new Vector3(0.8f, 0.8f, 4.2f);
Transform muzzle = GetOrCreateChild(recoil, "Muzzle");
muzzle.localPosition = new Vector3(0f, 0f, 4.25f);
Transform slotObject = GetOrCreateChild(root.transform, "Rocket Slot");
slotObject.localPosition = new Vector3(-2.2f, 1.25f, 0f);
slotObject.localRotation = Quaternion.Euler(0f, 90f, 0f);
slotObject.localScale = Vector3.one;
BoxCollider slotCollider = GetOrAdd<BoxCollider>(slotObject.gameObject);
slotCollider.isTrigger = true;
slotCollider.size = new Vector3(1.4f, 1.4f, 3.2f);
CannonRocketSlot slot = GetOrAdd<CannonRocketSlot>(slotObject.gameObject);
Transform snapPoint = GetOrCreateChild(slotObject, "Rocket Snap Point");
snapPoint.localPosition = Vector3.zero;
snapPoint.localRotation = Quaternion.identity;
Transform controls = GetOrCreateChild(root.transform, "Controls");
controls.localPosition = Vector3.zero;
controls.localRotation = Quaternion.identity;
controls.localScale = Vector3.one;
NetworkPhysicalLeverInteractable lever = CreateLever(controls);
NetworkButtonInteractable minus = CreateButton(
controls, "Timer Minus", new Vector3(1.8f, 1.4f, -1.4f), "Timer -");
NetworkButtonInteractable plus = CreateButton(
controls, "Timer Plus", new Vector3(3.1f, 1.4f, -1.4f), "Timer +");
TMP_Text timerText = CreateTimerText(controls);
SerializedObject serializedEmitter = new(emitter);
SetObject(serializedEmitter, "profile", cannonShockwave);
SetObject(serializedEmitter, "origin", muzzle);
serializedEmitter.ApplyModifiedPropertiesWithoutUndo();
SerializedObject serializedController = new(controller);
SetObject(serializedController, "config", config);
SetObject(serializedController, "rocketSlot", slot);
SetObject(serializedController, "rocketSnapPoint", snapPoint);
SetObject(serializedController, "mapController",
Object.FindFirstObjectByType<MapController>(FindObjectsInactive.Include));
SetObject(serializedController, "shotShockwave", emitter);
serializedController.ApplyModifiedPropertiesWithoutUndo();
SerializedObject serializedSlot = new(slot);
SetObject(serializedSlot, "snapPoint", snapPoint);
serializedSlot.ApplyModifiedPropertiesWithoutUndo();
SerializedObject serializedBinder = new(binder);
SetObject(serializedBinder, "cannon", controller);
SetObject(serializedBinder, "fireLever", lever);
SetObject(serializedBinder, "decreaseTimerButton", minus);
SetObject(serializedBinder, "increaseTimerButton", plus);
serializedBinder.ApplyModifiedPropertiesWithoutUndo();
SerializedObject serializedView = new(view);
SetObject(serializedView, "controller", controller);
SetObject(serializedView, "recoilVisual", recoil);
serializedView.ApplyModifiedPropertiesWithoutUndo();
CannonTimerView timerView = GetOrAdd<CannonTimerView>(timerText.gameObject);
SerializedObject serializedTimer = new(timerView);
SetObject(serializedTimer, "controller", controller);
SetObject(serializedTimer, "timerText", timerText);
serializedTimer.ApplyModifiedPropertiesWithoutUndo();
slot.Configure(controller);
EditorUtility.SetDirty(root);
return controller;
}
private static NetworkPhysicalLeverInteractable CreateLever(Transform parent)
{
Transform existing = parent.Find("Fire Lever");
GameObject root;
if (existing != null)
{
root = existing.gameObject;
}
else
{
GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(LeverPrefabPath);
root = (GameObject)PrefabUtility.InstantiatePrefab(prefab, parent);
root.name = "Fire Lever";
}
root.transform.localPosition = new Vector3(4.5f, 1.25f, -1.2f);
root.transform.localRotation = Quaternion.Euler(0f, -90f, 0f);
root.transform.localScale = Vector3.one * 0.65f;
NetworkPhysicalLeverInteractable lever =
root.GetComponent<NetworkPhysicalLeverInteractable>();
SerializedObject serialized = new(lever);
SetString(serialized, "interactionLabel", "Fire cannon");
SetBool(serialized, "initialPositionIsMaximum", false);
SetBool(serialized, "returnToInitialPositionAfterSwitch", true);
SetFloat(serialized, "automaticReturnDelay", 0.2f);
serialized.ApplyModifiedPropertiesWithoutUndo();
return lever;
}
private static NetworkButtonInteractable CreateButton(
Transform parent,
string name,
Vector3 localPosition,
string label)
{
Transform root = GetOrCreateChild(parent, name);
root.localPosition = localPosition;
root.localRotation = Quaternion.identity;
root.localScale = Vector3.one;
GetOrAdd<NetworkObject>(root.gameObject);
Transform visual = GetOrCreatePrimitive(root, "Button Visual", PrimitiveType.Cube);
visual.localPosition = Vector3.zero;
visual.localRotation = Quaternion.identity;
visual.localScale = new Vector3(0.8f, 0.8f, 0.3f);
NetworkButtonInteractable button = GetOrAdd<NetworkButtonInteractable>(root.gameObject);
SerializedObject serialized = new(button);
SetString(serialized, "interactionLabel", label);
SetFloat(serialized, "maximumInteractionDistance", 3.5f);
serialized.ApplyModifiedPropertiesWithoutUndo();
return button;
}
private static TMP_Text CreateTimerText(Transform parent)
{
Transform root = GetOrCreateChild(parent, "Timer Display");
root.localPosition = new Vector3(2.45f, 2.25f, -1.35f);
root.localRotation = Quaternion.Euler(0f, 180f, 0f);
root.localScale = Vector3.one * 0.12f;
TextMeshPro text = GetOrAdd<TextMeshPro>(root.gameObject);
text.alignment = TextAlignmentOptions.Center;
text.fontSize = 4f;
text.text = "INSERT ROCKET";
text.rectTransform.sizeDelta = new Vector2(12f, 3f);
return text;
}
private static void ConfigureMapMarker()
{
MapController map = Object.FindFirstObjectByType<MapController>(FindObjectsInactive.Include);
if (map == null)
return;
Transform root = map.transform.Find("Impact Markers");
if (root == null)
{
root = new GameObject("Impact Markers").transform;
root.SetParent(map.transform, false);
}
MapImpactMarkerView view = GetOrAdd<MapImpactMarkerView>(root.gameObject);
view.Configure(map.CoordinateSystem);
SerializedObject serializedMap = new(map);
SetObject(serializedMap, "impactMarkerView", view);
serializedMap.ApplyModifiedPropertiesWithoutUndo();
EditorUtility.SetDirty(map);
}
private static void EnsureDataFolder()
{
if (!AssetDatabase.IsValidFolder("Assets/CONTENT/Game/Data"))
AssetDatabase.CreateFolder("Assets/CONTENT/Game", "Data");
if (!AssetDatabase.IsValidFolder(DataFolder))
AssetDatabase.CreateFolder("Assets/CONTENT/Game/Data", "Cannon");
}
private static Transform GetOrCreateChild(Transform parent, string name)
{
Transform existing = parent.Find(name);
if (existing != null)
return existing;
GameObject child = new(name);
child.transform.SetParent(parent, false);
Undo.RegisterCreatedObjectUndo(child, $"Create {name}");
return child.transform;
}
private static Transform GetOrCreatePrimitive(
Transform parent,
string name,
PrimitiveType primitiveType)
{
Transform existing = parent.Find(name);
if (existing != null)
return existing;
GameObject primitive = GameObject.CreatePrimitive(primitiveType);
primitive.name = name;
primitive.transform.SetParent(parent, false);
Undo.RegisterCreatedObjectUndo(primitive, $"Create {name}");
return primitive.transform;
}
private static T GetOrAdd<T>(GameObject target) where T : Component
{
T component = target.GetComponent<T>();
return component != null ? component : Undo.AddComponent<T>(target);
}
private static void SetObject(SerializedObject target, string property, Object value) =>
target.FindProperty(property).objectReferenceValue = value;
private static void SetFloat(SerializedObject target, string property, float value) =>
target.FindProperty(property).floatValue = value;
private static void SetBool(SerializedObject target, string property, bool value) =>
target.FindProperty(property).boolValue = value;
private static void SetString(SerializedObject target, string property, string value) =>
target.FindProperty(property).stringValue = value;
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: fe3002dfbec1fe1458dcd6058b1486c3