Пирамида без огня, банка крови как в ванили, руны ножа на другой плоскости
- пирамида: огонь убран; включённая модель светится ярко (кристалл, глазницы), выключенная тускло; граница зоны - светящееся фиолетовое кольцо по земле (LineRenderer, точки опущены на рельеф) вместо огоньков; старые огни снимаются - банка крови: снято зеркалирование - стоит как ванильная, в руке - нож: руны перенесены на противоположную плоскость клинка Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
20ee89323d
commit
6ded684d2c
@@ -269,97 +269,108 @@ namespace NecromancerTome
|
|||||||
// `ToWorldPos()` (this feature's own position) instead of a dictionary-passed key.
|
// `ToWorldPos()` (this feature's own position) instead of a dictionary-passed key.
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
|
|
||||||
|
// 01.10.2026: огня больше нет. Своя модель (бандл necroward) светится сама - кристалл и
|
||||||
|
// глазницы в карте эмиссии; включённая пирамида светится ярко, выключенная тускло
|
||||||
|
// (MaterialPropertyBlock на рендерерах модели блока, материал общий не трогается).
|
||||||
|
static readonly MaterialPropertyBlock glowBlock = new MaterialPropertyBlock();
|
||||||
|
|
||||||
|
Transform ModelTransform()
|
||||||
|
{
|
||||||
|
World world = GameManager.Instance?.World;
|
||||||
|
if (world == null) return null;
|
||||||
|
Vector3i pos = ToWorldPos();
|
||||||
|
Chunk chunk = world.GetChunkFromWorldPos(pos) as Chunk;
|
||||||
|
BlockEntityData be = chunk?.GetBlockEntity(pos);
|
||||||
|
return be != null && be.bHasTransform ? be.transform : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ApplyModelGlow(bool on)
|
||||||
|
{
|
||||||
|
Transform t = ModelTransform();
|
||||||
|
if (t == null) return false;
|
||||||
|
Color c = on ? new Color(2.2f, 2.2f, 2.2f, 1f) : new Color(0.25f, 0.25f, 0.25f, 1f);
|
||||||
|
foreach (Renderer r in t.GetComponentsInChildren<Renderer>(true))
|
||||||
|
{
|
||||||
|
r.GetPropertyBlock(glowBlock);
|
||||||
|
glowBlock.SetColor("_EmissionColor", c);
|
||||||
|
r.SetPropertyBlock(glowBlock);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public void SpawnGlow()
|
public void SpawnGlow()
|
||||||
{
|
{
|
||||||
if (GameManager.Instance == null)
|
if (GameManager.Instance != null && !ApplyModelGlow(true)) glowPending = true;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Vector3i pos = ToWorldPos();
|
|
||||||
if (GameManager.Instance.HasBlockParticleEffect(pos))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// FIXED 2026-09-02 (user report: "горение пирамидки почему-то смещено на куб вверх и
|
|
||||||
// вбок"): World.blockToTransformPos(Vector3i) ALREADY returns (x+0.5, y, z+0.5)
|
|
||||||
// (decompiled to confirm - horizontally centered, y left raw/un-centered) - adding
|
|
||||||
// another +0.5 on x/z on top of that (the original bug) double-centered it, landing a
|
|
||||||
// full extra block over on both horizontal axes. Only the vertical lift (how far above
|
|
||||||
// the block the flame sits) is actually ours to add. Height LOWERED again same day
|
|
||||||
// ("сделай ниже не 2/3 куба" - after the sideways offset was gone, still sat too high):
|
|
||||||
// 1.2 (0.2 above the full block top) -> 0.6, under 2/3 (0.667) of a block as asked.
|
|
||||||
// Height lowered twice same day: 1.2 -> 0.6 ("сделай ниже не 2/3 куба"), then -> 0.4
|
|
||||||
// (direct follow-up: "Снизь высоту пламени до +0.4").
|
|
||||||
Vector3 worldPos = World.blockToTransformPos(pos) + new Vector3(0f, 0.4f, 0f);
|
|
||||||
// WardTint (not Color.white) as the ParticleEffect's own _color: ParticleEffect.
|
|
||||||
// SpawnParticleEffect applies this directly to any non-ParticleSystem Renderer on the
|
|
||||||
// prefab (decompiled to confirm) - covers a sub-emitter/glow sprite ApplyGlowTint's own
|
|
||||||
// ParticleSystem-only loop wouldn't reach, belt-and-suspenders alongside it.
|
|
||||||
GameManager.Instance.SpawnBlockParticleEffect(pos, new ParticleEffect(GlowParticleName, worldPos, Quaternion.identity, 0f, WardTint));
|
|
||||||
pendingTint.Add(pos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveGlow()
|
public void RemoveGlow()
|
||||||
{
|
{
|
||||||
if (GameManager.Instance == null)
|
if (GameManager.Instance == null) return;
|
||||||
{
|
// пирамиды, поставленные до 01.10, могли оставить огонь - снимаем, если есть
|
||||||
return;
|
|
||||||
}
|
|
||||||
Vector3i pos = ToWorldPos();
|
Vector3i pos = ToWorldPos();
|
||||||
if (GameManager.Instance.HasBlockParticleEffect(pos))
|
if (GameManager.Instance.HasBlockParticleEffect(pos)) GameManager.Instance.RemoveBlockParticleEffect(pos);
|
||||||
{
|
|
||||||
GameManager.Instance.RemoveBlockParticleEffect(pos);
|
|
||||||
}
|
|
||||||
pendingTint.Remove(pos);
|
pendingTint.Remove(pos);
|
||||||
|
if (!ApplyModelGlow(false)) glowPending = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Ring of glow points marking EffectRadius, keyed by y = -1000-i (real block
|
bool glowPending = true;
|
||||||
/// y-coordinates never go negative that far, so these keys can never collide with an
|
|
||||||
/// actual placed block's own glow key).</summary>
|
// Граница зоны (01.10: «вместо огня другие частицы, как круг у квеста на копание»):
|
||||||
|
// светящееся фиолетовое кольцо по земле - LineRenderer, точки опущены на рельеф лучом.
|
||||||
|
// Дочерний объект модели блока - поэтому сдвиги Origin и выгрузка чанка его не теряют.
|
||||||
|
GameObject ring;
|
||||||
|
|
||||||
public void SpawnZoneRing()
|
public void SpawnZoneRing()
|
||||||
{
|
{
|
||||||
if (GameManager.Instance == null)
|
if (ring != null) return;
|
||||||
|
Transform t = ModelTransform();
|
||||||
|
if (t == null) return;
|
||||||
|
ring = new GameObject("NecroWardRing");
|
||||||
|
ring.transform.SetParent(t, false);
|
||||||
|
var lr = ring.AddComponent<LineRenderer>();
|
||||||
|
lr.useWorldSpace = false; lr.loop = true;
|
||||||
|
const int n = 96;
|
||||||
|
lr.positionCount = n;
|
||||||
|
lr.widthMultiplier = 0.14f;
|
||||||
|
var mat = new Material(Shader.Find("Sprites/Default"));
|
||||||
|
lr.material = mat;
|
||||||
|
Color col = new Color(0.75f, 0.25f, 1f, 0.85f);
|
||||||
|
lr.startColor = col; lr.endColor = col;
|
||||||
|
lr.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; lr.receiveShadows = false;
|
||||||
|
Vector3 c = t.position;
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
{
|
{
|
||||||
return;
|
float ang = i * Mathf.PI * 2f / n;
|
||||||
}
|
Vector3 p = c + new Vector3(Mathf.Cos(ang) * EffectRadius, 0f, Mathf.Sin(ang) * EffectRadius);
|
||||||
Vector3i basePos = ToWorldPos();
|
if (Physics.Raycast(p + Vector3.up * 12f, Vector3.down, out RaycastHit hit, 30f, 65536))
|
||||||
// Same double-centering bug as SpawnGlow's own fix above - blockToTransformPos already
|
p.y = hit.point.y + 0.08f;
|
||||||
// centers x/z, only the vertical offset (0.5, mid-block height) is ours to add.
|
lr.SetPosition(i, t.InverseTransformPoint(p));
|
||||||
Vector3 center = World.blockToTransformPos(basePos) + new Vector3(0f, 0.5f, 0f);
|
|
||||||
for (int i = 0; i < ZoneRingPointCount; i++)
|
|
||||||
{
|
|
||||||
float angle = i * (360f / ZoneRingPointCount) * Mathf.Deg2Rad;
|
|
||||||
Vector3 point = center + new Vector3(Mathf.Cos(angle) * EffectRadius, 0f, Mathf.Sin(angle) * EffectRadius);
|
|
||||||
Vector3i key = new Vector3i(basePos.x, -1000 - i, basePos.z);
|
|
||||||
if (GameManager.Instance.HasBlockParticleEffect(key))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// ZoneRingParticleName (not GlowParticleName) - see that constant's own comment:
|
|
||||||
// user asked for the boundary to read as "some particles", not literal fire.
|
|
||||||
GameManager.Instance.SpawnBlockParticleEffect(key, new ParticleEffect(ZoneRingParticleName, point, Quaternion.identity, 0f, WardTint));
|
|
||||||
pendingTint.Add(key);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveZoneRing()
|
public void RemoveZoneRing()
|
||||||
{
|
{
|
||||||
if (GameManager.Instance == null)
|
if (ring != null) { UnityEngine.Object.Destroy(ring); ring = null; }
|
||||||
{
|
if (GameManager.Instance == null) return;
|
||||||
return;
|
// кольца из огоньков от версий до 01.10
|
||||||
}
|
|
||||||
Vector3i basePos = ToWorldPos();
|
Vector3i basePos = ToWorldPos();
|
||||||
for (int i = 0; i < ZoneRingPointCount; i++)
|
for (int i = 0; i < ZoneRingPointCount; i++)
|
||||||
{
|
{
|
||||||
Vector3i key = new Vector3i(basePos.x, -1000 - i, basePos.z);
|
Vector3i key = new Vector3i(basePos.x, -1000 - i, basePos.z);
|
||||||
if (GameManager.Instance.HasBlockParticleEffect(key))
|
if (GameManager.Instance.HasBlockParticleEffect(key)) GameManager.Instance.RemoveBlockParticleEffect(key);
|
||||||
{
|
|
||||||
GameManager.Instance.RemoveBlockParticleEffect(key);
|
|
||||||
}
|
|
||||||
pendingTint.Remove(key);
|
pendingTint.Remove(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Модель блока появляется позже, чем срабатывает OnAdded/загрузка, - поэтому
|
||||||
|
/// свечение и кольцо досоздаются из UpdateTick, когда модель уже есть.</summary>
|
||||||
|
void EnsureVisuals()
|
||||||
|
{
|
||||||
|
if (glowPending && ApplyModelGlow(EffectOn)) glowPending = false;
|
||||||
|
if (ZoneShown && ring == null) SpawnZoneRing();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>Mirrors ParticlePatch.cs's own tint technique (same ParticleSystem.MainModule
|
/// <summary>Mirrors ParticlePatch.cs's own tint technique (same ParticleSystem.MainModule
|
||||||
/// fields, same reasoning: the particle prefab always instantiates at its authored color,
|
/// fields, same reasoning: the particle prefab always instantiates at its authored color,
|
||||||
/// nothing in XML/the block-particle API can override that) - kept as its own copy here
|
/// nothing in XML/the block-particle API can override that) - kept as its own copy here
|
||||||
@@ -463,6 +474,7 @@ namespace NecromancerTome
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
EnsureVisuals();
|
||||||
|
|
||||||
for (int i = pendingTint.Count - 1; i >= 0; i--)
|
for (int i = pendingTint.Count - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user