斜角墙
This commit is contained in:
18
Source/WulaFallenEmpire/.gitignore
vendored
Normal file
18
Source/WulaFallenEmpire/.gitignore
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
# Compiled output
|
||||
bin/
|
||||
obj/
|
||||
|
||||
# Rider
|
||||
.idea/
|
||||
|
||||
# Visual Studio
|
||||
.vs/
|
||||
*.suo
|
||||
*.user
|
||||
*.userosf
|
||||
*.sln.docstates
|
||||
|
||||
# OS generated files
|
||||
.DS_Store
|
||||
.localized
|
||||
Thumbs.db
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,43 +1,59 @@
|
||||
using RimWorld;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
[StaticConstructorOnStartup]
|
||||
public class Building_Wula_DarkEnergy_Engine : Building_GravEngine
|
||||
// =========================================================================
|
||||
// 1. 抽象的引擎父类 (Abstract Base Class)
|
||||
// 它现在通过完全重写 DrawAt 方法来获得对绘制逻辑的控制权。
|
||||
// =========================================================================
|
||||
public abstract class Building_Wula_Engine_Base : Building_GravEngine
|
||||
{
|
||||
// 子类自己的静态只读字段
|
||||
private static readonly string _childStaticValue = "Child Value";
|
||||
private static readonly CachedMaterial Wula_DarkEnergy_OrbMat = new CachedMaterial("Wula/Building/Wula_DarkEnergy_Engine_Orb", ShaderDatabase.Cutout);
|
||||
// 契约:所有子类都必须提供一个用于绘制的能量球贴图。
|
||||
// 这个部分保持不变。
|
||||
protected abstract CachedMaterial OrbMat { get; }
|
||||
|
||||
// 通过实例属性暴露静态值
|
||||
protected override string InstanceValue => _childStaticValue;
|
||||
private static readonly CachedMaterial OrbMat = new CachedMaterial("Wula/Building/Wula_DarkEnergy_Engine_Orb", ShaderDatabase.Cutout);
|
||||
}
|
||||
public abstract class Building_Wula_DarkEnergy_Engine_Parent : Building_GravEngine
|
||||
{
|
||||
// 受保护的抽象属性(实例级别)
|
||||
protected abstract string InstanceValue { get; }
|
||||
|
||||
// 公共访问点
|
||||
public void PrintValue()
|
||||
// **关键修正**: 完全重写 DrawAt 方法
|
||||
protected override void DrawAt(Vector3 drawLoc, bool flip = false)
|
||||
{
|
||||
Console.WriteLine(InstanceValue);
|
||||
// --- 第 1 部分:复制父类的 `base.DrawAt(drawLoc, flip)` 逻辑 ---
|
||||
// 这会负责绘制建筑本身的基础图形。
|
||||
base.DrawAt(drawLoc, flip);
|
||||
|
||||
// --- 第 2 部分:复制并修改 `Building_GravEngine` 的绘制逻辑 ---
|
||||
if (base.Spawned)
|
||||
{
|
||||
// 这是原版引擎的“悬浮”动画逻辑,我们将其完整保留。
|
||||
if (Find.TickManager.TicksGame >= cooldownCompleteTick)
|
||||
{
|
||||
drawLoc.z += 0.5f * (1f + Mathf.Sin((float)Math.PI * 2f * (float)GenTicks.TicksGame / 500f)) * 0.3f;
|
||||
}
|
||||
|
||||
// 这是原版引擎的高度微调,我们也保留。
|
||||
drawLoc.y += 0.03658537f;
|
||||
|
||||
// 设置缩放,这部分也来自原版代码。
|
||||
Vector3 s = new Vector3(def.graphicData.drawSize.x, 1f, def.graphicData.drawSize.y);
|
||||
|
||||
// **最终修改**: 使用我们自己的 OrbMat 属性,而不是父类的私有变量!
|
||||
// 这使得子类可以自由决定能量球的外观。
|
||||
Graphics.DrawMesh(MeshPool.plane10Back, Matrix4x4.TRS(drawLoc, base.Rotation.AsQuat, s), this.OrbMat.Material, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Child : Parent
|
||||
{
|
||||
// 子类自己的静态只读字段
|
||||
private static readonly string _childStaticValue = "Child Value";
|
||||
|
||||
// 通过实例属性暴露静态值
|
||||
protected override string InstanceValue => _childStaticValue;
|
||||
// =========================================================================
|
||||
// 2. 具体的暗能量引擎子类 (Concrete Child Class)
|
||||
// 这个类完全不需要修改,它已经正确地实现了父类的要求。
|
||||
// =========================================================================
|
||||
[StaticConstructorOnStartup]
|
||||
public class Building_Wula_DarkEnergy_Engine : Building_Wula_Engine_Base
|
||||
{
|
||||
private static readonly CachedMaterial _darkEnergyOrbMat = new CachedMaterial("Wula/Building/Wula_DarkEnergy_Engine_Orb", ShaderDatabase.Cutout);
|
||||
|
||||
protected override CachedMaterial OrbMat => _darkEnergyOrbMat;
|
||||
}
|
||||
}
|
||||
193
Source/WulaFallenEmpire/SectionLayer_WulaHull.cs
Normal file
193
Source/WulaFallenEmpire/SectionLayer_WulaHull.cs
Normal file
@@ -0,0 +1,193 @@
|
||||
using LudeonTK;
|
||||
using RimWorld;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
// 定义了一个数据结构,用于从XML文件中加载我们的配置。
|
||||
public class WulaHullDef : Def
|
||||
{
|
||||
// 以下所有 public 字段都会由RimWorld的加载系统自动从XML同名节点中填充。
|
||||
public ThingDef targetDef;
|
||||
public ShaderTypeDef shaderType;
|
||||
|
||||
public string texPath_Corner_NW;
|
||||
public string texPath_Corner_NE;
|
||||
public string texPath_Corner_SW;
|
||||
public string texPath_Corner_SE;
|
||||
public string texPath_Diagonal_NW;
|
||||
public string texPath_Diagonal_NE;
|
||||
public string texPath_Diagonal_SW;
|
||||
public string texPath_Diagonal_SE;
|
||||
|
||||
// 提供一个全局静态访问点,方便在代码中随时获取配置,而无需传来传去。
|
||||
public static WulaHullDef Current => DefDatabase<WulaHullDef>.GetNamed("WulaHullConfig");
|
||||
}
|
||||
|
||||
// 这是核心的渲染类,继承自SectionLayer,负责在地图上绘制额外的视觉效果。
|
||||
public class SectionLayer_WulaHull : SectionLayer
|
||||
{
|
||||
public enum CornerType { None, Corner_NW, Corner_NE, Corner_SW, Corner_SE, Diagonal_NW, Diagonal_NE, Diagonal_SW, Diagonal_SE }
|
||||
|
||||
private static readonly Vector2[] UVs = { new Vector2(0f, 0f), new Vector2(0f, 1f), new Vector2(1f, 1f), new Vector2(1f, 0f) };
|
||||
[TweakValue("WulaHullCorners", 0f, 2f)]
|
||||
private static float HullCornerScale = 2f;
|
||||
|
||||
private static CachedMaterial mat_Corner_NW, mat_Corner_NE, mat_Corner_SW, mat_Corner_SE, mat_Diagonal_NW, mat_Diagonal_NE, mat_Diagonal_SW, mat_Diagonal_SE;
|
||||
private static readonly float cornerAltitude = AltitudeLayer.BuildingOnTop.AltitudeFor();
|
||||
private static bool initalized;
|
||||
|
||||
private static readonly IntVec3[] Directions = { IntVec3.North, IntVec3.East, IntVec3.South, IntVec3.West, IntVec3.North + IntVec3.West, IntVec3.North + IntVec3.East, IntVec3.South + IntVec3.East, IntVec3.South + IntVec3.West };
|
||||
private static bool[] tmpChecks = new bool[Directions.Length];
|
||||
|
||||
// 获取要使用的着色器。优先从XML配置中读取,如果未配置则使用一个安全合理的默认值。
|
||||
private static Shader WallShader => WulaHullDef.Current.shaderType?.Shader ?? ShaderDatabase.CutoutComplex;
|
||||
|
||||
public override bool Visible => true;
|
||||
|
||||
public SectionLayer_WulaHull(Section section) : base(section)
|
||||
{
|
||||
// 告诉游戏,当建筑、地形等发生变化时,需要重绘我们的图层。
|
||||
relevantChangeTypes = (ulong)MapMeshFlagDefOf.Buildings | (ulong)MapMeshFlagDefOf.Terrain | (ulong)MapMeshFlagDefOf.Things | (ulong)MapMeshFlagDefOf.Roofs;
|
||||
}
|
||||
|
||||
// 这是一个性能优化技巧,确保贴图和材质只在第一次使用时被加载和创建,而不是每次重绘都加载。
|
||||
private static void EnsureInitialized()
|
||||
{
|
||||
if (!initalized)
|
||||
{
|
||||
initalized = true;
|
||||
WulaHullDef config = WulaHullDef.Current;
|
||||
|
||||
mat_Corner_NW = new CachedMaterial(config.texPath_Corner_NW, WallShader);
|
||||
mat_Corner_NE = new CachedMaterial(config.texPath_Corner_NE, WallShader);
|
||||
mat_Corner_SW = new CachedMaterial(config.texPath_Corner_SW, WallShader);
|
||||
mat_Corner_SE = new CachedMaterial(config.texPath_Corner_SE, WallShader);
|
||||
mat_Diagonal_NW = new CachedMaterial(config.texPath_Diagonal_NW, WallShader);
|
||||
mat_Diagonal_NE = new CachedMaterial(config.texPath_Diagonal_NE, WallShader);
|
||||
mat_Diagonal_SW = new CachedMaterial(config.texPath_Diagonal_SW, WallShader);
|
||||
mat_Diagonal_SE = new CachedMaterial(config.texPath_Diagonal_SE, WallShader);
|
||||
}
|
||||
}
|
||||
|
||||
// 游戏引擎会定期调用这个方法来更新和重绘我们的图层。
|
||||
public override void Regenerate()
|
||||
{
|
||||
ClearSubMeshes(MeshParts.All);
|
||||
Map map = base.Map;
|
||||
TerrainGrid terrGrid = map.terrainGrid;
|
||||
foreach (IntVec3 item in section.CellRect)
|
||||
{
|
||||
if (ShouldDrawCornerPiece(item, map, terrGrid, out var cornerType, out var color))
|
||||
{
|
||||
CachedMaterial material = GetMaterial(cornerType);
|
||||
IntVec3 offset = GetOffset(cornerType);
|
||||
bool addGravshipMask = false;
|
||||
bool addIndoorMask = IsCornerIndoorMasked(item, cornerType, map);
|
||||
AddQuad(material.Material, item + offset, HullCornerScale, cornerAltitude, color, addGravshipMask, addIndoorMask);
|
||||
}
|
||||
}
|
||||
FinalizeMesh(MeshParts.All);
|
||||
}
|
||||
|
||||
// 这是整个框架的核心判断逻辑。
|
||||
// 它检查给定的坐标,分析其周围8个方向的建筑,来决定是否需要绘制斜角,以及绘制哪种类型的斜角。
|
||||
public static bool ShouldDrawCornerPiece(IntVec3 pos, Map map, TerrainGrid terrGrid, out CornerType cornerType, out Color color)
|
||||
{
|
||||
cornerType = CornerType.None;
|
||||
color = Color.white;
|
||||
if (pos.GetEdifice(map) != null) return false;
|
||||
TerrainDef terrainDef = terrGrid.FoundationAt(pos);
|
||||
if (terrainDef != null && terrainDef.IsSubstructure) return false;
|
||||
ThingDef targetDef = WulaHullDef.Current.targetDef;
|
||||
if (targetDef == null) { Log.ErrorOnce("WulaHullConfig has a null targetDef. Please check WulaHullDefs.xml.", 168168168); return false; }
|
||||
for (int i = 0; i < Directions.Length; i++) { tmpChecks[i] = (pos + Directions[i]).GetEdificeSafe(map)?.def == targetDef; }
|
||||
if (tmpChecks[0] && tmpChecks[3] && !tmpChecks[2] && !tmpChecks[1]) cornerType = (tmpChecks[4] ? CornerType.Corner_NW : CornerType.Diagonal_NW);
|
||||
else if (tmpChecks[0] && tmpChecks[1] && !tmpChecks[2] && !tmpChecks[3]) cornerType = (tmpChecks[5] ? CornerType.Corner_NE : CornerType.Diagonal_NE);
|
||||
else if (tmpChecks[2] && tmpChecks[1] && !tmpChecks[0] && !tmpChecks[3]) cornerType = (tmpChecks[6] ? CornerType.Corner_SE : CornerType.Diagonal_SE);
|
||||
else if (tmpChecks[2] && tmpChecks[3] && !tmpChecks[0] && !tmpChecks[1]) cornerType = (tmpChecks[7] ? CornerType.Corner_SW : CornerType.Diagonal_SW);
|
||||
if (cornerType == CornerType.None) return false;
|
||||
for (int j = 0; j < 4; j++) { if (tmpChecks[j]) { color = (pos + Directions[j]).GetEdificeSafe(map).DrawColor; break; } }
|
||||
return true;
|
||||
}
|
||||
|
||||
private static CachedMaterial GetMaterial(CornerType edgeType)
|
||||
{
|
||||
EnsureInitialized();
|
||||
switch (edgeType)
|
||||
{
|
||||
case CornerType.Corner_NW: return mat_Corner_NW;
|
||||
case CornerType.Corner_NE: return mat_Corner_NE;
|
||||
case CornerType.Corner_SW: return mat_Corner_SW;
|
||||
case CornerType.Corner_SE: return mat_Corner_SE;
|
||||
case CornerType.Diagonal_NW: return mat_Diagonal_NW;
|
||||
case CornerType.Diagonal_NE: return mat_Diagonal_NE;
|
||||
case CornerType.Diagonal_SW: return mat_Diagonal_SW;
|
||||
case CornerType.Diagonal_SE: return mat_Diagonal_SE;
|
||||
default: throw new System.ArgumentOutOfRangeException("edgeType", edgeType, null);
|
||||
}
|
||||
}
|
||||
|
||||
private static IntVec3 GetOffset(CornerType cornerType)
|
||||
{
|
||||
switch (cornerType)
|
||||
{
|
||||
case CornerType.Corner_NE: case CornerType.Diagonal_NE: return new IntVec3(0, 0, 0);
|
||||
case CornerType.Corner_NW: case CornerType.Diagonal_NW: return new IntVec3(-1, 0, 0);
|
||||
case CornerType.Corner_SE: case CornerType.Diagonal_SE: return new IntVec3(0, 0, -1);
|
||||
case CornerType.Corner_SW: case CornerType.Diagonal_SW: return new IntVec3(-1, 0, -1);
|
||||
default: return IntVec3.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
private void AddQuad(Material mat, IntVec3 c, float scale, float altitude, Color color, bool addGravshipMask, bool addIndoorMask)
|
||||
{
|
||||
LayerSubMesh subMesh = GetSubMesh(mat);
|
||||
AddQuad(subMesh, c.ToVector3(), scale, altitude, color);
|
||||
if (addGravshipMask)
|
||||
{
|
||||
Texture2D srcTex = subMesh.material.mainTexture as Texture2D;
|
||||
Color color2 = subMesh.material.color;
|
||||
Material material = MaterialPool.MatFrom(srcTex, ShaderDatabase.GravshipMaskMasked, color2);
|
||||
AddQuad(GetSubMesh(material), c.ToVector3(), scale, altitude, color);
|
||||
}
|
||||
if (addIndoorMask)
|
||||
{
|
||||
Texture2D srcTex2 = subMesh.material.mainTexture as Texture2D;
|
||||
Color color3 = subMesh.material.color;
|
||||
Material material2 = MaterialPool.MatFrom(srcTex2, ShaderDatabase.IndoorMaskMasked, color3);
|
||||
AddQuad(GetSubMesh(material2), c.ToVector3(), scale, altitude, color);
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddQuad(LayerSubMesh sm, Vector3 c, float scale, float altitude, Color color)
|
||||
{
|
||||
int count = sm.verts.Count;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
sm.verts.Add(new Vector3(c.x + UVs[i].x * scale, altitude, c.z + UVs[i].y * scale));
|
||||
sm.uvs.Add(UVs[i % 4]);
|
||||
sm.colors.Add(color);
|
||||
}
|
||||
sm.tris.Add(count);
|
||||
sm.tris.Add(count + 1);
|
||||
sm.tris.Add(count + 2);
|
||||
sm.tris.Add(count);
|
||||
sm.tris.Add(count + 2);
|
||||
sm.tris.Add(count + 3);
|
||||
}
|
||||
|
||||
private static bool IsCornerIndoorMasked(IntVec3 c, CornerType cornerType, Map map)
|
||||
{
|
||||
switch (cornerType)
|
||||
{
|
||||
case CornerType.Corner_NE: case CornerType.Diagonal_NE: if (!c.Roofed(map)) return (c + IntVec3.East).Roofed(map); return true;
|
||||
case CornerType.Corner_NW: case CornerType.Diagonal_NW: if (!c.Roofed(map)) return (c + IntVec3.West).Roofed(map); return true;
|
||||
case CornerType.Corner_SE: case CornerType.Diagonal_SE: if (!c.Roofed(map)) return (c + IntVec3.East).Roofed(map); return true;
|
||||
case CornerType.Corner_SW: case CornerType.Diagonal_SW: if (!c.Roofed(map)) return (c + IntVec3.West).Roofed(map); return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
@@ -17,7 +17,7 @@
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<OutputPath>..\..\1.6\Assemblies\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
@@ -32,7 +32,8 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Assembly-CSharp">
|
||||
<HintPath>..\..\..\..\RimWorldWin64_Data\Managed\Assembly-CSharp.dll</HintPath>
|
||||
<HintPath>..\..\..\..\..\..\common\RimWorld\RimWorldWin64_Data\Managed\Assembly-CSharp.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
@@ -42,13 +43,19 @@
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="UnityEngine">
|
||||
<HintPath>..\..\..\..\..\..\common\RimWorld\RimWorldWin64_Data\Managed\UnityEngine.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.CoreModule">
|
||||
<HintPath>..\..\..\..\RimWorldWin64_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||
<HintPath>..\..\..\..\..\..\common\RimWorld\RimWorldWin64_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Building_Wula_DarkEnergy_Engine.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="SectionLayer_WulaHull.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user